javascript - 在 SVG 圆圈内环绕文本

标签 javascript html css d3.js

我使用 D3 创建了一个气泡图....

但我的问题是......我无法将文字包裹在大圆圈和小圆圈内..

我写了一个wrap函数...好像不行....

如果你运行我下面的代码,你会看到我的需求...请给我一些建议...我被这个问题困扰了很长时间...

代码

     <style type="text/css">
        #mainBubble {
            background: #fff;
            border: solid 1px #ddd;
            box-shadow: 0 0 4px rgba(0,0,0,0);
            font: 10px sans-serif;
            height: 800px;
            position: relative;
            width: 80%;
        }

            #mainBubble svg {
                left: 0;
                position: absolute;
                top: 0;
            }

            #mainBubble circle.topBubble {
                fill: #aaa;
                stroke: #666;
                stroke-width: 1.5px;
            }
    </style>
    <script type="text/javascript" src="../D3/d3.min.js" charset="utf-8"></script>
    <title>TORUS Bubble
    </title>

    <div id="mainBubble" style="height: 618px;">
        <svg class="mainBubbleSVG" width="882.436" height="618">
            <text id="bubbleItemNote" x="10" y="426.218" font-size="12" dominant-baseline="middle" alignment-baseline="middle" style="fill: rgb(136, 136, 136);">D3.js bubble menu developed by Shipeng Sun (sunsp.gis@gmail.com), Institute of Environment, University of Minnesota, and University of Springfield, Illinois.</text></svg></div>
    <script>
        var w = window.innerWidth * 0.90 * 1;
        var h = Math.ceil(w * 0.90);
        var oR = 0;
        var nTop = 0;

        var svgContainer = d3.select("#mainBubble")
                             .style("height", h + "px");



        var svg = d3.select("#mainBubble").append("svg")
                     .attr("class", "mainBubbleSVG")
                     .attr("width", w)
                     .attr("height", h)
                     .on("mouseleave", function () { return resetBubbles(); });

        var mainNote = svg.append("text")
                         .attr("id", "bubbleItemNote")
                         .attr("x", 10)
                         .attr("y", w / 2 - 15)
                         .attr("font-size", 12)
                         .attr("dominant-baseline", "middle")
                         .attr("alignment-baseline", "middle")
                         .style("fill", "#888888")
                         .text(function (d) { return "Welcome To TORUS aPaas 6.0 Powered By D3"; });


        function wrapText(text, width) {
            text.each(function () {
                var textEl = d3.select(this),
                    words = textEl.text().split(/\s+/).reverse(),
                    word
                line = [],
                linenumber = 0,
                lineHeight = 1.1, // ems
                y = textEl.attr('y'),
                dx = parseFloat(textEl.attr('dx') || 0),
                dy = parseFloat(textEl.attr('dy') || 0),
                tspan = textEl.text(null).append('tspan').attr('x', 0).attr('y', y).attr('dy', dy + 'em');

                while (word = words.pop()) {
                    line.push(word);
                    tspan.text(line.join(' '));
                    if (tspan.node().getComputedTextLength() > width) {
                        line.pop();
                        tspan.text(line.join(' '));
                        line = [word];
                        tspan = textEl.append('tspan').attr('x', 0).attr('y', y).attr('dx', dx).attr('dy', ++linenumber * lineHeight + dy + 'em').text(word);
                    }
                }
            });
        }


        d3.json("main_bubble.txt", function (error, root) {
            console.log(error);

            var bubbleObj = svg.selectAll(".topBubble")
                                 .data(root.children)
                                 .enter().append("g")
                                 .attr("id", function (d, i) { return "topBubbleAndText_" + i });

            console.log(root);
            nTop = root.children.length;
            oR = w / (1 + 3 * nTop);

            h = Math.ceil(w / nTop * 2);
            svgContainer.style("height", h + "px");

            var colVals = d3.scale.category10();

            bubbleObj.append("circle")
                    .attr("class", "topBubble")
                    .attr("id", function (d, i) { return "topBubble" + i; })
                    .attr("r", function (d) { return oR; })
                    .attr("cx", function (d, i) { return oR * (3 * (1 + i) - 1); })
                    .attr("cy", (h + oR) / 3)
                    .style("fill", function (d, i) { return colVals(i); }) // #1f77b4
                    .style("opacity", 0.3)
                    .on("mouseover", function (d, i) { return activateBubble(d, i); });


            bubbleObj.append("text")
                    .attr("class", "topBubbleText")
                    .attr("x", function (d, i) { return oR * (3 * (1 + i) - 1); })
                    .attr("y", (h + oR) / 3)
                    .style("fill", function (d, i) { return colVals(i); }) // #1f77b4
                    .attr("font-size", 30)
                    .attr("text-anchor", "middle")
                    .attr("dominant-baseline", "middle")
                    .attr("alignment-baseline", "middle")
                    .text(function (d) { return d.name })
                    //.call(wrapText, 150)

                    .on("mouseover", function (d, i) { return activateBubble(d, i); });


            for (var iB = 0; iB < nTop; iB++) {
                var childBubbles = svg.selectAll(".childBubble" + iB)
                    .data(root.children[iB].children)
                    .enter().append("g");

                //var nSubBubble = Math.floor(root.children[iB].children.length/2.0);   

                childBubbles.append("circle")
                    .attr("class", "childBubble" + iB)
                    .attr("id", function (d, i) { return "childBubble_" + iB + "sub_" + i; })
                    .attr("r", function (d) { return oR/ 2.0; })
                    .attr("cx", function (d, i) { return (oR * (3 * (iB + 1) - 1) + oR * 1.5 * Math.cos((i - 1) * 45 / 180 * 3.1415926)); })
                    .attr("cy", function (d, i) { return ((h + oR) / 3 + oR * 1.5 * Math.sin((i - 1) * 45 / 180 * 3.1415926)); })
                    .attr("cursor", "pointer")
                    .style("opacity", 0.5)
                    .style("fill", "#eee")
                    .on("click", function (d, i) {
                        window.open(d.address);
                    })
                .on("mouseover", function (d, i) {
                    //window.alert("say something");
                    var noteText = "";
                    if (d.note == null || d.note == "") {
                        noteText = d.address;
                    } else {
                        noteText = d.note;
                    }
                    d3.select("#bubbleItemNote").text(noteText);
                })
                .append("svg:title")
                .text(function (d) { return d.address; });

                childBubbles.append("text")
                    .attr("class", "childBubbleText" + iB)
                    .attr("x", function (d, i) { return (oR * (3 * (iB + 1) - 1) + oR * 1.5 * Math.cos((i - 1) * 45 / 180 * 3.1415926)); })
                    .attr("y", function (d, i) { return ((h + oR) / 3 + oR * 1.5 * Math.sin((i - 1) * 45 / 180 * 3.1415926)); })
                    .style("opacity", 0.5)
                    .attr("text-anchor", "middle")
                    .style("fill", function (d, i) { return colVals(iB); }) // #1f77b4
                    .attr("font-size", 6)
                    .attr("cursor", "pointer")
                    .attr("dominant-baseline", "middle")
                    .attr("alignment-baseline", "middle")
                    .text(function (d) { return d.name })
                    //.call(wrapText, 150)

                    .on("click", function (d, i) {
                        window.open(d.address);
                    });

            }


        });

        resetBubbles = function () {
            w = window.innerWidth * 0.68 * 0.95;
            oR = w / (1 + 3 * nTop);

            h = Math.ceil(w / nTop * 2);
            svgContainer.style("height", h + "px");

            mainNote.attr("y", h - 15);

            svg.attr("width", w);
            svg.attr("height", h);

            d3.select("#bubbleItemNote").text("Welcome To TORUS aPaas 6.0 Powered By D3");

            var t = svg.transition()
                       .duration(750);

            t.selectAll(".topBubble")
                .attr("r", function (d) { return oR; })
                .attr("cx", function (d, i) { return oR * (3 * (1 + i) - 1); })
                .attr("cy", (h + oR) / 3);

            t.selectAll(".topBubbleText")
              .attr("font-size", 30)
              .attr("x", function (d, i) { return oR * (3 * (1 + i) - 1); })
              .attr("y", (h + oR) / 3);

            for (var k = 0; k < nTop; k++) {
                t.selectAll(".childBubbleText" + k)
                        .attr("x", function (d, i) { return (oR * (3 * (k + 1) - 1) + oR * 1.5 * Math.cos((i - 1) * 45 / 180 * 3.1415926)); })
                        .attr("y", function (d, i) { return ((h + oR) / 3 + oR * 1.5 * Math.sin((i - 1) * 45 / 180 * 3.1415926)); })
                        .attr("font-size", 6)
                        .style("opacity", 0.5);

                t.selectAll(".childBubble" + k)
                        .attr("r", function (d) { return oR / 3.0; })
                        .style("opacity", 0.5)
                        .attr("cx", function (d, i) { return (oR * (3 * (k + 1) - 1) + oR * 1.5 * Math.cos((i - 1) * 45 / 180 * 3.1415926)); })
                        .attr("cy", function (d, i) { return ((h + oR) / 3 + oR * 1.5 * Math.sin((i - 1) * 45 / 180 * 3.1415926)); });

            }
        }


        function activateBubble(d, i) {
            // increase this bubble and decrease others
            var t = svg.transition()
                .duration(d3.event.altKey ? 7500 : 350);

            t.selectAll(".topBubble")
                .attr("cx", function (d, ii) {
                    if (i == ii) {
                        // Nothing to change
                        return oR * (3 * (1 + ii) - 1) - 0.6 * oR * (ii - 1);
                    } else {
                        // Push away a little bit
                        if (ii < i) {
                            // left side
                            return oR * 0.6 * (3 * (1 + ii) - 1);
                        } else {
                            // right side
                            return oR * (nTop * 3 + 1) - oR * 0.6 * (3 * (nTop - ii) - 1);
                        }
                    }
                })
                .attr("r", function (d, ii) {
                    if (i == ii)
                        return oR * 1.8;
                    else
                        return oR * 0.8;
                });

            t.selectAll(".topBubbleText")
                .attr("x", function (d, ii) {
                    if (i == ii) {
                        // Nothing to change
                        return oR * (3 * (1 + ii) - 1) - 0.6 * oR * (ii - 1);
                    } else {
                        // Push away a little bit
                        if (ii < i) {
                            // left side
                            return oR * 0.6 * (3 * (1 + ii) - 1);
                        } else {
                            // right side
                            return oR * (nTop * 3 + 1) - oR * 0.6 * (3 * (nTop - ii) - 1);
                        }
                    }
                })
                .attr("font-size", function (d, ii) {
                    if (i == ii)
                        return 30 * 1.5;
                    else
                        return 30 * 0.6;
                });

            var signSide = -1;
            for (var k = 0; k < nTop; k++) {
                signSide = 1;
                if (k < nTop / 2) signSide = 1;
                t.selectAll(".childBubbleText" + k)
                    .attr("x", function (d, i) { return (oR * (3 * (k + 1) - 1) - 0.6 * oR * (k - 1) + signSide * oR * 2.5 * Math.cos((i - 1) * 45 / 180 * 3.1415926)); })
                    .attr("y", function (d, i) { return ((h + oR) / 3 + signSide * oR * 2.5 * Math.sin((i - 1) * 45 / 180 * 3.1415926)); })
                    .attr("font-size", function () {
                        return (k == i) ? 12 : 6;
                    })
                    .style("opacity", function () {
                        return (k == i) ? 1 : 0;
                    });

                t.selectAll(".childBubble" + k)
                    .attr("cx", function (d, i) { return (oR * (3 * (k + 1) - 1) - 0.6 * oR * (k - 1) + signSide * oR * 2.5 * Math.cos((i - 1) * 45 / 180 * 3.1415926)); })
                    .attr("cy", function (d, i) { return ((h + oR) / 3 + signSide * oR * 2.5 * Math.sin((i - 1) * 45 / 180 * 3.1415926)); })
                    .attr("r", function () {
                        return (k == i) ? (oR * 0.55) : (oR / 3.0);
                    })
                    .style("opacity", function () {
                        return (k == i) ? 1 : 0;
                    });
            }
        }

        window.onresize = resetBubbles;
    </script

请将以下json数据保存为main_bubble.txt

-------------
JSON data
-------------
{
    "name": "bubble",
    "children": [
        {
            "name": "Dsg Tools",
            "description": "Atlas of Global Agriculture",
            "children": [
                {
                    "name": "Geography",
                    "address": "http://gli.environment.umn.edu",
                    "note": "Global crop geography, including precipitation, temperature, crop area, etc."
                },
                {
                    "name": "Crop Land",
                    "address": "http://d3js.org"
                },
                {
                    "name": "Crop Yields",
                    "address": "http://environment.umn.edu",
                    "note": "Maize, wheat, rice, and soybean yields in 2000"
                },
                {
                    "name": "Water Need",
                    "address": "http://environment.umn.edu",
                    "note": "Maize, wheat, rice, and soybean yields in 2000"
                },
                {
                    "name": "Pollution Control",
                    "address": "http://environment.umn.edu",
                    "note": "Maize, wheat, rice, and soybean yields in 2000"
                },
                {
                    "name": "Toxic Waste",
                    "address": "http://environment.umn.edu",
                    "note": "Maize, wheat, rice, and soybean yields in 2000"
                }
            ]
        },
        {
            "name": "App Assembler",
            "description": "Virtual Lab of Global Agriculture",
            "children": [
                {
                    "name": "Excess Nutrient",
                    "address": "http://d3js.org",
                    "note": "Prototype Infographics on Excess Fertilizer Nutrients"
                },
                {
                    "name": "Yield Gap",
                    "address": "http://d3js.org",
                    "note": "The gap between attainable yields and actual yields, with modeled yields assuming the percentage of gap closed."
                },
                {
                    "name": "Fertilizer",
                    "address": "http://sunsp.net"
                },
                {
                    "name": "Fertilizer",
                    "address": "http://sunsp.net"
                },
                {
                    "name": "Fertilizer",
                    "address": "http://sunsp.net"
                },
                {
                    "name": "Fertilizer",
                    "address": "http://sunsp.net"
                }
            ]
        },
        {
            "name": "App Package",
            "description": "Profiles of Country",
            "children": [
                {
                    "name": "Efficiency",
                    "address": "http://d3js.org"
                },
                {
                    "name": "Excess Nutrient",
                    "address": "http://d3js.org"
                },
                {
                    "name": "Economy",
                    "address": "http://d3js.org"
                },
                {
                    "name": "Agriculture",
                    "address": "http://uis.edu/ens"
                }
            ]
        },
        {
            "name": "Common Svs",
            "description": "Crop Data in 5 minutes grid",
            "children": [
                {
                    "name": "Geography",
                    "address": "http://www.earthstat.org/"
                },
                {
                    "name": "Crop Land",
                    "address": "http://www.earthstat.org/"
                },
                {
                    "name": "Crop Yields",
                    "address": "http://www.earthstat.org/"
                }
            ]
        }
    ]
}

最佳答案

给你:

<!DOCTYPE html>
<html>
    <head>
        <style>
            svg {
                background:lightblue;                    
            }
        </style> 
        <title>cirular text</title> 
    </head>
    <body>
        <svg height="100%" width="100%">
            <path id ="tpath" 
                d="M100 200
                A 170 170, 0 1 0, 100 199"  
                fill="none" stroke="blue"/>
            <text font-size="20pt">
                <textPath xlink:href="#tpath">
                    The one true ring !
                </textPath>
            </text>
        </svg>
    </body>
</html>    

学习 SVG 的好地方是:

SVG Tutorial - Jenkov.com

本系列教程介绍了 SVG(可缩放矢量图形)的大部分功能。

关于javascript - 在 SVG 圆圈内环绕文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35692357/

相关文章:

php - Onchange 事件与 jquery slider 一起使用

javascript - 在 JQuery Listview 之后填充

html - css - 忽略行高的 block 元素

javascript - 带有 jquery 多选插件的 Angular js

python - 在 Python 3 中为 Selenium 的弹出菜单项查找 CSS 选择器

html - IE7 问题 : How to expand parent div's height with dynamic content of the child div?

javascript - 尽管类序列相同,但 CSS 优先级发生变化

javascript - Backbone.js 动态多级路由

javascript - 如何在express.js中编写具有多个参数的API

javascript - 如何将一些文本动画化到圆形 div 中的随机位置