score:1

If you set the desired margin:

var margin = 20;

You can avoid the triangles having their center positioned within that margin:

.attr("transform", function(d) 
    { return "translate(" + (margin + Math.random()*(width - margin)) 
    + "," + (margin + Math.random()*(height - margin)) + ")"; 
})

Have in mind that this doesn't take in consideration the fact that the triangles have different sizes: it sets the same margin for everyone.

Here is the fiddle: https://jsfiddle.net/7qkqtwmu/

score:3

You can easily use the element bounding box size when you set it's translate value.

It's strange, but for triangles to fully be inside svg, using bbox height does not work. Shapes width are a couple of pixels larger than their heights and using that value in computations works.

var width = 250;
var height = 250;
var number = 30;
var borderSize = 1;
var body = d3.select("body");
var triangle = d3.symbol()
  .type(d3.symbolTriangle);

var svg = body.append("svg")
  .attr("width", width)
  .attr("height", height)
  .style("border", "1px solid black");


function drawTriangles(number) {
  for (var i = 0; i < number; i++) {
    var dim = Math.random() * 300;
    svg.append("path")
      .attr("d", triangle.size(dim))
      .attr("transform", function (d) {
        var boundingBox = this.getBBox();
        var elementWidth = Math.ceil(boundingBox.width);
        var randomXOffset = Math.random() * (width - elementWidth - 2 * borderSize) + elementWidth/2 + borderSize;
        var randomYOffset = Math.random() * (height - elementWidth - 2 * borderSize) + elementWidth/2 + borderSize;
        return "translate(" + randomXOffset + "," + randomYOffset + ")";
      })
      .attr("fill", "rgb(" + parseInt(Math.random() * 255) + "," + parseInt(Math.random() * 255) + "," + parseInt(Math.random() * 255) + ")")
      .attr("opacity", 2)
      .attr("class", "path" + i);
  }
}

drawTriangles(number);
<script src="https://d3js.org/d3.v4.min.js"></script>

<body>
</body>


Related Query