我使用此代码制作了 d3.js 图表 bl.ocks.org/d3noob/8375092
我正在尝试更改单词的颜色。在每个单词的实例中,我都希望改变该颜色。例如,如果您查看图表,有 A 的第一个女儿和 A 的女儿。我想将文本“女儿”的颜色更改为红色。我想将“2级之子:B”全部更改为蓝色。 (忽略大的高度和宽度 - 在我的元素中,我的可折叠图表中有 50 个术语 - 但在这个问题中只包含了一些)。
我尝试在CSS中更改所有文本的颜色,但它没有出现。当我检查元素时,颜色将显示为“蓝色”,但文本显示为黑色。我也尝试在 HTML 中使用 ,但我不知道如何处理变量 tree.Data,因为它是在 JavaScript 中。
我是编码初学者。感谢您的帮助!
var treeData = [
{
"name": "Top Level",
"parent": "null",
"children": [
{
"name": "Level 2: A",
"parent": "Top Level",
"children": [
{
"name": "First Daughter of A",
"parent": "Level 2: A"
},
{
"name": "Daughter of A",
"parent": "Level 2: A"
}
]
},
{
"name": "Level 2: B",
"parent": "Top Level",
"children": [
{
"name": "Son of Level 2: B",
"parent": "Level 2: B"
}
]
}
]
}
];
// ************** Generate the tree diagram *****************
var margin = {top: 20, right: 120, bottom: 20, left: 250},
width = 2000 - margin.right - margin.left,
height = 2000 - margin.top - margin.bottom;
var i = 0,
duration = 750,
root;
var tree = d3.layout.tree()
.size([height, width]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var svg = d3.select("body").append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
root = treeData[0];
root.x0 = height / 2;
root.y0 = 0;
update(root);
d3.select(self.frameElement).style("height", "500px");
function update(source) {
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 180; });
// Update the nodes…
var node = svg.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", click);
nodeEnter.append("circle")
.attr("r", 1e-6)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeEnter.append("text")
.attr("x", function(d) { return d.children || d._children ? -13 : 13; })
.attr("dy", ".35em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.text(function(d) { return d.name; })
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.select("circle")
.attr("r", 10)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeUpdate.select("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
.remove();
nodeExit.select("circle")
.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// Update the links…
var link = svg.selectAll("path.link")
.data(links, function(d) { return d.target.id; });
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", function(d) {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
// Toggle children on click.
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
.node {
cursor: pointer;
}
.block{
width:5%;
height:10%;
}
.top{
width: 95%;
margin-left: 5%;
color: black;
}
.no{
color:black;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 3px;
}
.node text {
color: Blue;
font-weight: bold;
font: 12px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 2px;
}
<div class="block"></div>
<div class="top">
<h1>Title</h1>
<h2>Click nodes to expand each level</h2>
<h3>Key</h3>
<div class="no">
<h4>No capability</h4>
</div>
<div class="adhoc">
<h4>Another heading</h4>
</div>
<h4>Another heading4</h4>
<h4>Heading 4</h4>
<h4>Final heading 4</h4>
</div>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script src="myChart.js"></script>
<link rel= "stylesheet" href="./myStyle.css">
最佳答案
在 SVG 中,为了给单个单词着色,您需要在文本元素中使用 tspan。这意味着搜索文本元素,查找匹配的字符串,并将它们替换为包含匹配单词的新子 tspan 元素。
突出显示(更改颜色)文本元素中指定的短语/单词:
一种方法可能是:
function highlight(selection,word) {
selection.each(function() {
this.innerHTML = this.textContent.replace(new RegExp(word, "ig"),(w)=>"<tspan>"+w+"</tspan>")
})
}
此函数需要选择(文本)元素和要查找的单词。它搜索文本元素的文本内容以查找匹配的字符串,并将匹配的字符串替换为包含匹配字符串的 tspan。匹配文本时不区分大小写,但保留原始文本中的大小写。
在下面的代码片段中,只需在文本框中键入即可动态突出显示文本:
var svg = d3.select("svg");
var data = [
"You can't direct the wind, but you can adjust your sails",
"If you chase two rabbits, you will lose them both.",
"If you speak the truth, have a foot in the stirrup.",
"One doesn't discover new lands without losing sight of the shore.",
"The whole is more than the sum of its parts."
]
var textElements = svg.selectAll(null)
.data(data)
.join("text")
.text(d=>d)
.attr("x",20)
.attr("y",(d,i) => i* 30 + 30);
function highlight(selection,word) {
selection.each(function() {
this.innerHTML = this.textContent.replace(new RegExp(word, "ig"),(w)=>"<tspan>"+w+"</tspan>")
})
}
d3.select("#text").on("keyup", function() {
textElements.call(highlight, this.value);
//alternatively: highlight(textElements,this.value);
})
tspan {
fill: orange;
stroke: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.0/d3.min.js"></script>
<div><input type="text" id="text"/></div>
<svg width="500" height="250"></svg>
用矩形突出显示:
我们还可以更花哨一点,使用荧光笔描边,这需要添加矩形,为此我们可以使用 tspan 作为连接的数据来创建矩形:
var svg = d3.select("svg");
var data = [
"You can't direct the wind, but you can adjust your sails",
"If you chase two rabbits, you will lose them both.",
"If you speak the truth, have a foot in the stirrup.",
"One doesn't discover new lands without losing sight of the shore.",
"The whole is more than the sum of its parts.",
]
var textElements = svg.selectAll(null)
.data(data)
.join("text")
.text(d=>d)
.attr("x",20)
.attr("y",(d,i) => i* 30 + 30);
function highlight(selection,word,rectContainer) {
selection.each(function() {
this.innerHTML = this.textContent.replace(new RegExp(word, "ig"),(w)=>"<tspan>"+w+"</tspan>")
})
// join, color, positoin the rectangles:
rectContainer.selectAll(".highlight")
.data(selection.selectAll("tspan").nodes())
.join("rect")
.attr("class","highlight")
.datum(d=>d.getBBox())
.attr("x", d=>d.x)
.attr("y", d=>d.y)
.attr("width", d=>d.width)
.attr("height", d=>d.height)
.attr("fill","yellow")
.lower();
}
d3.select("#text").on("keyup", function() {
textElements.call(highlight, this.value, svg);
//alternatively: highlight(textElements,this.value);
})
tspan {
fill: orange;
stroke: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.0/d3.min.js"></script>
<div><input type="text" id="text"/></div>
<svg width="500" height="250"></svg>
使用一种突出显示样式突出显示多个短语/单词:
如果我们想用相同的颜色突出显示多个短语,我们可以修改正则表达式:
let ex = new RegExp(words.join("|"),"gi");
selection.each(function() {
this.innerHTML = this.textContent.replace(ex, "ig"),(w)=>"<tspan>"+w+"</tspan>")
})
var svg = d3.select("svg");
var data = [
"You can't direct the wind, but you can adjust your sails",
"If you chase two rabbits, you will lose them both.",
"If you speak the truth, have a foot in the stirrup.",
"One doesn't discover new lands without losing sight of the shore.",
"The whole is more than the sum of its parts.",
]
var textElements = svg.selectAll(null)
.data(data)
.join("text")
.text(d=>d)
.attr("x",20)
.attr("y",(d,i) => i* 30 + 30);
function highlight(selection,words,rectContainer) {
let ex = new RegExp(words.join("|"),"gi");
selection.each(function() {
this.innerHTML = this.textContent.replace(ex,(w)=>"<tspan>"+w+"</tspan>")
})
// join, color, positoin the rectangles:
rectContainer.selectAll(".highlight")
.data(selection.selectAll("tspan").nodes())
.join("rect")
.attr("class","highlight")
.datum(d=>d.getBBox())
.attr("x", d=>d.x)
.attr("y", d=>d.y)
.attr("width", d=>d.width)
.attr("height", d=>d.height)
.attr("fill","yellow")
.lower();
}
d3.selectAll("input").on("keyup", function() {
var words = d3.selectAll("input").nodes().map(function(n) { return n.value; });
textElements.call(highlight, words, svg);
})
d3.select("input").dispatch("keyup");
tspan {
fill: orange;
stroke: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.0/d3.min.js"></script>
<div><input type="text" value="you" id="text1"/></div>
<div><input type="text" value="two" id="text2"/></div>
<svg width="500" height="250"></svg>
突出显示多个具有不同样式的短语/单词:
处理不同短语的多个 tspan 和矩形时,挑战会更加困难。为此,我们需要修改突出显示函数以匹配多个字符串,为了实现灵活性,我们还将避免硬编码类。这需要比以前更好的数据管理,因此对突出显示功能进行了一些更改以适应这一点。
为了完成此任务,我们将迭代提供的单词列表,并根据矩形填充和文本填充的指定颜色数组为它们分配颜色。我们将添加 tspan,并使用 tspan 的内容和 tspan 的 bbox 作为数据,向前传递到用于添加矩形的连接。
对于矩形和文本,我们将使用突出显示功能直接给元素填充,例如:
function highlight(selection,words,rectContainer) {
// create a pool of colors available:
let textColors = ["crimson","steelblue"];
let rectColors = ["yellow","#ccc","orange","#eee"];
// assign colors to words:
let colors = {}
words.forEach((w,i)=>{
colors[w.toLowerCase()] = {
text: textColors[i%textColors.length],
rect: rectColors[i%rectColors.length]
}
})
// create a regex experssion:
let ex = new RegExp(words.join("|"),"gi");
// Create the tspans:
selection.each(function() {
this.innerHTML = this.textContent.replace(ex,(w)=>"<tspan>"+w+"</tspan>")
})
// Select the tspans, bind data to them, color them:
let tspans = selection.selectAll("tspan")
.datum((d,i,n)=>{
return {word:n[i].textContent.toLowerCase()}
})
.attr("fill", d=>colors[d.word].text)
.each((d,i,n)=>{ d.bbox = n[i].getBBox() })
// Conduct a join of rectangles, color them, place them:
rectContainer.selectAll(".highlight")
.data(tspans.data())
.join("rect")
.attr("class","highlight")
.attr("x", d=>d.bbox.x)
.attr("y", d=>d.bbox.y)
.attr("width", d=>d.bbox.width)
.attr("height", d=>d.bbox.height)
.attr("fill", d=>colors[d.word].rect)
.lower();
}
var svg = d3.select("svg");
var data = [
"You can't direct the wind, but you can adjust your sails",
"If you chase two rabbits, you will lose them both.",
"If you speak the truth, have a foot in the stirrup.",
"One doesn't discover new lands without losing sight of the shore.",
"The whole is more than the sum of its parts."
]
var textElements = svg.selectAll(null)
.data(data)
.join("text")
.text(d=>d)
.attr("x",20)
.attr("y",(d,i) => i* 30 + 30);
function highlight(selection,words,rectContainer) {
// create a pool of colors available:
let textColors = ["crimson","steelblue"];
let rectColors = ["yellow","#ccc","orange","#eee"];
// assign colors to words:
let colors = {}
words.forEach((w,i)=>{
colors[w.toLowerCase()] = {
text: textColors[i%textColors.length],
rect: rectColors[i%rectColors.length]
}
})
// create a regex experssion:
let ex = new RegExp(words.join("|"),"gi");
// Create the tspans:
selection.each(function() {
this.innerHTML = this.textContent.replace(ex,(w)=>"<tspan>"+w+"</tspan>")
})
// Select the tspans:
let tspans = selection.selectAll("tspan")
.datum((d,i,n)=>{
return {word:n[i].textContent.toLowerCase()}
})
.attr("fill", d=>colors[d.word].text)
.each((d,i,n)=>{ d.bbox = n[i].getBBox() })
// Conduct a join of rectangles:
rectContainer.selectAll(".highlight")
.data(tspans.data())
.join("rect")
.attr("class","highlight")
.attr("x", d=>d.bbox.x)
.attr("y", d=>d.bbox.y)
.attr("width", d=>d.bbox.width)
.attr("height", d=>d.bbox.height)
.attr("fill", d=>colors[d.word].rect)
.lower();
}
// cycle through some words:
let wordlist = [
["you","the","can"],
["stirrup","chase","discover","whole"],
["if"]
]
let i = 0;
highlight(textElements,wordlist[i++%3],svg)
setInterval(function(){
highlight(textElements,wordlist[i++%3],svg) },
1000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.0/d3.min.js"></script>
<svg width="500" height="250"></svg>
上面应该产生:
关于Javascript 在文本中查找单词并动态改变颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68485651/