score:1

You are missing the x and y attributes of the rect. Since these give the top-left point, you can set the rect at the centre of the svg with:

// get centre of svg and rect width and height
var svgCentre = {x: width/ 2, y: height / 2};
var rectDims = {w: width / 5, h: height / 5};
var rect = g
  .append("rect")
  .attr("x", svgCentre.x - (rectDims.w / 2)) // offset left by half rect width
  .attr("y", svgCentre.y - (rectDims.h / 2)) // offset up by half rect height
  .attr("width", rectDims.w)
  .attr("height", rectDims.h)
  .style("fill", "white");

Where svgCentre is half the width and half the height of the svg. Then you can offset the top-left point of the rect by half the width and half the height of the rect.

You mention you want to rotate the rect around the centre point - you can re-use the svgCentre coordinates in the rotate transform:

.attrTween("transform", () => {
  var i = d3.interpolate(0, 360); // full circle
  // set centre of rotation at centre of svg
  return t => `rotate(${i(t)}, ${svgCentre.x}, ${svgCentre.y})`; 
});

attrTween is figuring out that over the course of the transition you need to rotate through 360 degrees i.e. 5.55 degrees per millisecond. The return t => ... is saying return a function with an argument t which is some time in the duration that when passed to the d3.interpolate function (assigned to i) will resolve to the amount of degrees to rotate based on the time elapsed. This is then put into the string attribute of the transform for that moment in time.

Example:

const height = window.innerHeight - 20,
  width = window.innerWidth - 20;

var body = d3
  .select("body")
  .style("text-align", "center")
  .style("background", "#3c3c3c");

var svg = d3
  .select("body")
  .append("svg")
  .attr("height", height)
  .attr("width", width)
  .style("background", "red")
  .style("display", "inline-block");

var g = svg.append("g")

// get centre of svg and rect width and height
var svgCentre = {x: width/ 2, y: height / 2};
var rectDims = {w: width / 5, h: height / 5};
var rect = g
  .append("rect")
  .attr("x", svgCentre.x - (rectDims.w / 2)) // offset left by half rect width
  .attr("y", svgCentre.y - (rectDims.h / 2)) // offset up by half rect height
  .attr("width", rectDims.w)
  .attr("height", rectDims.h)
  .style("fill", "white")

// rotate rect through 360 degrees with centre of rotation at svg centre
rect.transition()
  .duration(2000)
  .attrTween("transform", () => {
    var i = d3.interpolate(0, 360); // full circle
    // set centre of rotation at centre of svg
    return t => `rotate(${i(t)}, ${svgCentre.x}, ${svgCentre.y})`; 
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>


Related Query