Akshat G
Akshat G

Reputation: 214

D3.js rotate shape without rotating text inside

I want to create rotate animation in a d3.js chart. With help of Gilsha I was able to create a chart like this :enter image description here

Now on click of any of the outer circles i want to rotate all circles and align the one which was clicked in the place of "hllooo" circle.

I have copied one angletween which is rotating the circles but the problem is that text inside that circle also gets rotated and creates something like this:

enter image description here

As you can see the text is also rotated which i dont want. The code for transform function is:

function angleTween(d, i) {
            var angle = 360 - ((i + 1) * 70);
            var i = d3.interpolate(0, 90);
            return function (t) {
                return "rotate(" + i(t) + ")";
            };
        }

So how to keep text unrotated and just rotate the shape ?

Upvotes: 1

Views: 1511

Answers (1)

Gilsha
Gilsha

Reputation: 14591

Calulcate the x and y attributes of text elements by using SVGPoint matrixTransform.

earth.on('click', function() {
    texts.style("opacity", 0);
    earthLayer
        .transition()
        .duration(2000)
        .attrTween("transform", angleTween)
        .each("end", function() {
            var svgEl = this.ownerSVGElement;
            var angle = d3.select(this).attr("transform").match(/\d+/g)[0];
            var matrix = svgEl.createSVGMatrix().rotate(angle);
            texts.each(function(d, i) {
                var point = this.ownerSVGElement.createSVGPoint();
                point.x = +d.cx;
                point.y = +d.cy;
                point = point.matrixTransform(matrix);
                d3.select(this).attr("x", point.x).attr("y", point.y);
            });
            texts.style("opacity", 1);
        });
});

var now = d3.time.year.floor(new Date());

var spacetime = d3.select('body');
var width = 960,
    height = 700,
    radius = Math.min(width, height);

var radii = {
    "sun": radius / 6,
    "earthOrbit": radius / 2.5,
    "earth": radius / 15,
    "moonOrbit": radius / 16,
    "moon": radius / 96
};

// Space
var svg = spacetime.append("svg")
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

// Sun
var sun = svg.append("circle")
    .attr("class", "sun")
    .attr("r", radii.sun)
    //.style("fill", "rgba(255, 204, 0, 1.0)");
    .style("stroke", "#f58c2e")
    .style("stroke-width", "10")
    .style("fill", "none");

// Earth's orbit
var orbit = svg.append("circle")
    .attr("class", "earthOrbit")
    .attr("r", radii.earthOrbit)
    .style("fill", "none")
    .style("stroke", "#bababa")
    .style("stroke-width", "30");

// Current position of Earth in its orbit
var earthOrbitPosition = d3.svg.arc()
    .outerRadius(radii.earthOrbit + 1)
    .innerRadius(radii.earthOrbit - 1)
    .startAngle(0)
    .endAngle(0);

svg.append("path")
    .attr("class", "earthOrbitPosition")
    .attr("d", earthOrbitPosition)
    .style("fill", "rgba(255, 204, 0, 0.75)");


// Time of day
var day = d3.svg.arc()
    .outerRadius(radii.earth)
    .innerRadius(0)
    .startAngle(0)
    .endAngle(0);

svg.append("path")
    .attr("class", "day")
    .attr("d", day)
    .attr("transform", "translate(0," + -radii.earthOrbit + ")")
    .style("fill", "rgba(53, 110, 195, 1.0)");


// Current position of the Moon in its orbit
var moonOrbitPosition = d3.svg.arc()
    .outerRadius(radii.moonOrbit + 1)
    .innerRadius(radii.moonOrbit - 1)
    .startAngle(0)
    .endAngle(0);

svg.append("path")
    .attr("class", "moonOrbitPosition")
    .attr("d", moonOrbitPosition)
    .attr("transform", "translate(0," + -radii.earthOrbit + ")")
    .style("fill", "rgba(113, 170, 255, 0.75)");

function getCirclePoints(points, radius, center) {
    var circlePositions = [];
    var slice = 2 * Math.PI / points;
    for (var i = 0; i < points; i++) {
        var angle = slice * i;
        var newX = (center.X + radius * Math.cos(angle));
        var newY = (center.Y + radius * Math.sin(angle));
        circlePositions.push({
            cx: newX,
            cy: newY
        });
    }
    return circlePositions;
}

var circlePositions = getCirclePoints(10, radii.earthOrbit, {
    X: 0,
    Y: 0
});
var earthLayer = svg.append("g").classed("earthLayer", true);
var textLayer = svg.append("g").classed("textLayer", true);
var earth = earthLayer.selectAll(".earth").data(circlePositions)
    .enter()
    .append("circle")
    .attr("cx", function(d) {
        return d.cx;
    })
    .attr("cy", function(d) {
        return d.cy;
    })
    .attr("class", "earth")
    .style("fill", "white")
    .attr("r", radii.earth)
    .style("stroke", "#bababa")
    .style("stroke-width", "10");

texts = textLayer.selectAll("text").data(circlePositions).enter().append("text").attr("x", function(d) {
    return d.cx
}).attr("dx", -radii.earth / 2).attr("y", function(d) {
    return d.cy
}).text(function(d, i) {
    if (i == 0) return "hllooo";
    else return "hllooo" + i;
});

earth.on('click', function() {
    texts.style("opacity", 0);
    earthLayer
        .transition()
        .duration(2000)
        .attrTween("transform", angleTween)
        .each("end", function() {
            var svgEl = this.ownerSVGElement;
            var angle = d3.select(this).attr("transform").match(/\d+/g)[0];
            var matrix = svgEl.createSVGMatrix().rotate(angle);
            texts.each(function(d, i) {
                var point = this.ownerSVGElement.createSVGPoint();
                point.x = +d.cx;
                point.y = +d.cy;
                point = point.matrixTransform(matrix);
                d3.select(this).attr("x", point.x).attr("y", point.y);
            });
            texts.style("opacity", 1);
        });
});

function angleTween(d, i) {
    var angle = 360 - ((i + 1) * 70);
    var i = d3.interpolate(0, angle);
    return function(t) {
        return "rotate(" + i(t) + ")";
    };
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Hope this helps.

Upvotes: 2

Related Questions