如何在SVG/D3中围绕其质心旋转文本(垂直翻转)? [英] How to rotate text around its centroid (vertically flip) in SVG / D3?

查看:81
本文介绍了如何在SVG/D3中围绕其质心旋转文本(垂直翻转)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些文本对象,它们的标记点均匀分布在一个圆周围.多亏了此文章,我能够正确定位这两个点和文本对象,但圆的左半球上的标签需要旋转180度(垂直翻转)才能更清晰.

I have text objects labeling points that are evenly spaced around a circle. Thanks to this article, I am able to correctly position both the points and text objects but the labels on the left hemisphere of the circle need to be rotated 180 degrees (flipped vertically) to be more legible.

我以为可以先将文本对象围绕其原点旋转,然后再将其旋转到圆周围的适当位置,但是无法确定如何定位每个文本对象的中心位置.

I thought I could rotate the text object about its own origin before rotating it to the appropriate position around the circle but was unable to determine how to locate the center position of each text object.

如何为圆形左半球(angle> = PI/2&&< = PI * 1.5)上的文本对象围绕它们的中心旋转文本对象?还是在那里更好的技术?

How can I rotate text objects about their center for those on the left hemisphere of the circle (angle>= PI/2 && angle<=PI*1.5)? Or is there a better technique to use?

<style type="text/css">
    * {
        font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
        font-size: 13px;
    }
    circle {
        fill: steelblue;
        fill-opacity: .8;
    }

    circle:hover {
        fill: orange;
        fill-opacity: .8;
    }
</style>

<div id="canvas"></div>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.v2.min.js"></script>
<script type="text/javascript">
    (function () {
        var paddding = 250;

        var createNodes = function () {

            var nodeData = [
                { id: 0, label: 'AAA' },
                { id: 1, label: 'BBB' },
                { id: 2, label: 'CCC' },
                { id: 3, label: 'DDD' },
                { id: 4, label: 'EEE' },
                { id: 5, label: 'FFF' },
                { id: 6, label: 'GGG' },
                { id: 7, label: 'HHH' }
            ];

            var radius = 100;
            var nodes = [],
                width = (radius * 2) + paddding,
                height = (radius * 2) + paddding,
                angle,
                x,
                y,
                i;

            var numNodes = nodeData.length;

            for (i = 0; i < numNodes; i++) {
                angle = (i / (numNodes / 2)) * Math.PI; 
                x = (radius * Math.cos(angle)) + (width / 2);
                y = (radius * Math.sin(angle)) + (width / 2);
                nodes.push({ 'id': i, 'x': x, 'y': y, 'label': nodeData[i].label, 'angle': angle });
            }
            return nodes;
        }

        var createSvg = function (radius, callback) {
            d3.selectAll('svg').remove();
            var svg = d3.select('#canvas').append('svg:svg')
                .attr('width', (radius * 2) + paddding)
                .attr('height', (radius * 2) + paddding);
            callback(svg);
        }

        var createElements = function (svg, nodes, elementRadius) {
            element = svg.selectAll('circle')
                .data(nodes)
                .enter().append('svg:circle')
                .attr('r', elementRadius)
                .attr('cx', function (d, i) { return d.x; })
                .attr('cy', function (d, i) { return d.y; });

            element = svg.selectAll('text')
                .data(nodes)
                .enter().append('svg:text')
                .text(function (d, i) { return d.label + " - " + d.angle.toFixed(2) + ", " + (d.angle*180/Math.PI); })
                .attr('x', function (d, i) { return nodes[0].x + 15; }) // add 15 for spacing off point
                .attr('y', function (d, i) { return nodes[0].y; })
                .attr("dy", ".35em")
                .style("alignment-baseline","middle")
                .style("text-anchor", "start")
                .attr("transform", function(d,i) {
                    return "rotate(" + (d.angle * 180) / Math.PI + ", 225, 225)";})
                ;
        }

        var draw = function () {
            var radius = 100;
            var nodes = createNodes();

            createSvg(radius, function (svg) {
                createElements(svg, nodes, 10);
            });
        }

        $(document).ready(function () {
            draw();
        });
    })();
</script>

推荐答案

如果要反转圆左侧的标签.您可以实现不同的方法.一种方法是在添加文本时修改文本的三个属性:

If you want to reverse the labels for those on the left side of the circle. You can achieve different ways. One way is by modifying three attributes of the text as you append it:

.attr('x', function (d, i) { return nodes[0].x + 15; })  
.style("text-anchor", "start")
.attr("transform", function(d,i) {
  return "rotate(" + (d.angle * 180) / Math.PI + ", 225, 225)"
})

如果仅修改其中一些,则可能无法获得所需的结果.

If you modify only some of these, you might not get the results you are looking for.

text-end

Modification of text-end

这是必需的,因为您的文本将从定义的起点开始,并且文本的长度可能可变,因此定义起点将比所需的更为复杂.对于需要翻转的点,需要使用:

This is needed as your text will start away from the point you are defining, and as the text may have variable length, defining a start point will be more complex than necessary. For points you need to flip, you'll need to use:

.style("text-anchor", "end")

transformx

Modification of the transform and x

文本需要旋转180度才能正确显示;但是,如果您修改此功能以向任何文本添加180度,则文本将出现在显示屏的错误一侧.因此,您还需要将x设置为新值,以便它出现在显示屏的正确一侧:

The text needs to be rotated 180 degrees so that it is right way up; however, if you modify this function to add 180 degrees to any text, then the text will appear on the wrong side of the display. So, you'll need to set x to a new value too, so that it appears on the correct side of the display:

.attr('x', function (d, i) { return nodes[0].x - 215; }) // radius * 2, add 15 for spacing off point

.attr("transform", function(d,i) {
  return "rotate(" + ((d.angle * 180) / Math.PI - 180) + ", 225, 225)"
})

总的来说,像这样:

(function () {
        var paddding = 250;

        var createNodes = function () {

            var nodeData = [
                { id: 0, label: 'AAA' },
                { id: 1, label: 'BBB' },
                { id: 2, label: 'CCC' },
                { id: 3, label: 'DDD' },
                { id: 4, label: 'EEE' },
                { id: 5, label: 'FFF' },
                { id: 6, label: 'GGG' },
                { id: 7, label: 'HHH' }
            ];

            var radius = 100;
            var nodes = [],
                width = (radius * 2) + paddding,
                height = (radius * 2) + paddding,
                angle,
                x,
                y,
                i;

            var numNodes = nodeData.length;

            for (i = 0; i < numNodes; i++) {
                angle = (i / (numNodes / 2)) * Math.PI; 
                x = (radius * Math.cos(angle)) + (width / 2);
                y = (radius * Math.sin(angle)) + (width / 2);
                nodes.push({ 'id': i, 'x': x, 'y': y, 'label': nodeData[i].label, 'angle': angle });
            }
            return nodes;
        }

        var createSvg = function (radius, callback) {
            d3.selectAll('svg').remove();
            var svg = d3.select('#canvas').append('svg:svg')
                .attr('width', (radius * 2) + paddding)
                .attr('height', (radius * 2) + paddding);
            callback(svg);
        }

        var createElements = function (svg, nodes, elementRadius) {
            element = svg.selectAll('circle')
                .data(nodes)
                .enter().append('svg:circle')
                .attr('r', elementRadius)
                .attr('cx', function (d, i) { return d.x; })
                .attr('cy', function (d, i) { return d.y; });

            element = svg.selectAll('text')
                .data(nodes)
                .enter().append('svg:text')
                .text(function (d, i) { return d.label + " - " + d.angle.toFixed(2) + ", " + (d.angle*180/Math.PI); })
                .attr('x', function (d, i) { return nodes[0].x - 215; }) // radius * 2, add 15 for spacing off point
                .attr('y', function (d, i) { return nodes[0].y; })
                .attr("dy", ".35em")
                .style("alignment-baseline","middle")
                .style("text-anchor", "end")
                .attr("transform", function(d,i) {
                    return "rotate(" + ((d.angle * 180) / Math.PI - 180) + ", 225, 225)";})
                ;
        }

        var draw = function () {
            var radius = 100;
            var nodes = createNodes();

            createSvg(radius, function (svg) {
                createElements(svg, nodes, 10);
            });
        }

        $(document).ready(function () {
            draw();
        });
    })();

* {
        font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
        font-size: 13px;
    }
    circle {
        fill: steelblue;
        fill-opacity: .8;
    }

    circle:hover {
        fill: orange;
        fill-opacity: .8;
    }

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.v2.min.js"></script>
<div id="canvas"></div>

但是,现在右侧的标签是上下颠倒的.剩下要做的就是确定标签是落在右半边还是左半边,并根据此标签分配适当的属性.

However, now the labels on the right are upside down. All that is left is to determine is whether a label falls on the right half or the left half and assign the appropriate attributes based on this.

零度指向右侧,而不是图的顶部.因此,您需要确定d.angle是小于90度(右下)还是大于270度(右上),如果是,则可以应用原始代码.如果没有,那么您需要使用上面的代码翻转标签:

Zero degrees points to the right, it is not the top of the diagram. Therefore, you need to ascertain if d.angle is less than 90 degrees (bottom right) or more than 270 degrees (top right), if so, your original code can be applied. If not, then you need to flip the label using the above code:

(function () {
        var paddding = 250;

        var createNodes = function () {

            var nodeData = [
                { id: 0, label: 'AAA' },
                { id: 1, label: 'BBB' },
                { id: 2, label: 'CCC' },
                { id: 3, label: 'DDD' },
                { id: 4, label: 'EEE' },
                { id: 5, label: 'FFF' },
                { id: 6, label: 'GGG' },
                { id: 7, label: 'HHH' }
            ];

            var radius = 100;
            var nodes = [],
                width = (radius * 2) + paddding,
                height = (radius * 2) + paddding,
                angle,
                x,
                y,
                i;

            var numNodes = nodeData.length;

            for (i = 0; i < numNodes; i++) {
                angle = (i / (numNodes / 2)) * Math.PI; 
                x = (radius * Math.cos(angle)) + (width / 2);
                y = (radius * Math.sin(angle)) + (width / 2);
                nodes.push({ 'id': i, 'x': x, 'y': y, 'label': nodeData[i].label, 'angle': angle });
            }
            return nodes;
        }

        var createSvg = function (radius, callback) {
            d3.selectAll('svg').remove();
            var svg = d3.select('#canvas').append('svg:svg')
                .attr('width', (radius * 2) + paddding)
                .attr('height', (radius * 2) + paddding);
            callback(svg);
        }

        var createElements = function (svg, nodes, elementRadius) {
            element = svg.selectAll('circle')
                .data(nodes)
                .enter().append('svg:circle')
                .attr('r', elementRadius)
                .attr('cx', function (d, i) { return d.x; })
                .attr('cy', function (d, i) { return d.y; });

            element = svg.selectAll('text')
                .data(nodes)
                .enter().append('svg:text')
                .text(function (d, i) { return d.label + " - " + d.angle.toFixed(2) + ", " + (d.angle*180/Math.PI); })
                .attr('x', function (d, i) { 
                   if (d.angle > Math.PI/2  && d.angle < 1.5 * Math.PI) {
                     return nodes[0].x - 215 } 
                   else {  
                     return  nodes[0].x + 15; 
                     }
                }) 
                .attr('y', function (d, i) { return nodes[0].y; })
                .attr("dy", ".35em")
                .style("alignment-baseline","middle")
                .style("text-anchor", function(d) { 
                  if (d.angle > Math.PI/2  && d.angle < 1.5 * Math.PI) {
                     return "end" 
                   }
                   else {
                     return "start";
                   }
                })
                .attr("transform", function(d,i) {
                  if (d.angle > Math.PI/2  && d.angle < 1.5 * Math.PI) {
                     return "rotate(" + ((d.angle * 180) / Math.PI - 180) + ", 225, 225)";
                   }
                   else {
                     return "rotate(" + ((d.angle * 180) / Math.PI) + ", 225, 225)" 
                   }
                 })
                ;
        }

        var draw = function () {
            var radius = 100;
            var nodes = createNodes();

            createSvg(radius, function (svg) {
                createElements(svg, nodes, 10);
            });
        }

        $(document).ready(function () {
            draw();
        });
    })();

* {
        font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
        font-size: 13px;
    }
    circle {
        fill: steelblue;
        fill-opacity: .8;
    }

    circle:hover {
        fill: orange;
        fill-opacity: .8;
    }

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.v2.min.js"></script>
<div id="canvas"></div>

这篇关于如何在SVG/D3中围绕其质心旋转文本(垂直翻转)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆