D3.js旋转形状而不旋转文本

时间:2015-11-25 11:26:39

标签: javascript d3.js rotation

我想在d3.js图表​​中创建旋转动画。在Gilsha的帮助下,我能够创建如下图表:enter image description here

现在点击任何一个外圆圈我要旋转所有圆圈并对齐在" hllooo"圈。

我复制了一个旋转圆圈的角度,但问题是该圆圈内的文字也会旋转并创建如下内容:

enter image description here

正如你所看到的那样,文字也是旋转的,我不想要。 transform函数的代码是:

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

那么如何保持文本不旋转并只旋转形状?

1 个答案:

答案 0 :(得分:2)

使用SVGPoint matrixTransform计算文本元素的x和y属性。

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) + ")";
    };
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
&#13;
&#13;
&#13;

希望这有帮助。