我使用D3创建了一个气泡图....
但是我的问题是......我无法将文字包裹在圆圈内的大圆圈和小圆圈中。
我已经编写了一个包装函数......它似乎无法正常工作......
<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/"
}
]
}
]
}
答案 0 :(得分:-1)
你可以单独使用SVG完成整个事情:
<svg width="100%" height="100%" viewBox="0 0 1000 300"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path id="MyPath"
d="M 100 200
C 200 100 300 0 400 100
C 500 200 600 300 700 200
C 800 100 900 100 900 100" />
</defs>
<use xlink:href="#MyPath" fill="none" stroke="red" />
<text font-family="Verdana" font-size="42.5">
<textPath xlink:href="#MyPath">
We go up, then we go down, then up again
</textPath>
</text>
<!-- Show outline of the viewport using 'rect' element -->
<rect x="1" y="1" width="998" height="298"
fill="none" stroke="black" stroke-width="2" />
</svg>
这会沿着一条上下抛物线的路径写入文本。将路径更改为圆圈。
答案 1 :(得分:-1)
你在这里:
<!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的大部分(可缩放矢量图形)功能。