简体   繁体   English

Javascript在文本中查找单词并动态更改颜色

[英]Javascript find a word in text and change color dynamically

I made a d3.js chart using this code bl.ocks.org/d3noob/8375092我使用此代码制作了 d3.js 图表bl.ocks.org/d3noob/8375092

I am trying to change the color of a word.我正在尝试更改单词的颜色。 In every instance of a word, I would like to have that color changed.在一个词的每一个实例中,我都希望改变那个颜色。 For example, if you look at the chart, there is First Daughter of A and Daughter of A. I would like to change the color of the text "Daughter" to red.例如,如果您查看图表,有 A 的第一个女儿和 A 的女儿。我想将文本“女儿”的颜色更改为红色。 And I would like to change all of "Son of Level 2: B" to the color blue.我想将“2级之子:B”的所有内容更改为蓝色。 (Ignore the large height and width -in my project I have 50 terms in my collapsible chart - but only included a few in this question). (忽略大的高度和宽度 - 在我的项目中,我的可折叠图表中有 50 个术语 - 但在这个问题中只包含了几个)。

I tried in CSS to change the color of all text, but it does not appear.我尝试在 CSS 中更改所有文本的颜色,但它没有出现。 When I inspect an element, the color will show as "blue" but the text appears black.当我检查一个元素时,颜色将显示为“蓝色”,但文本显示为黑色。 I also tried in HTML to use , but I don't know what to do for the variable tree.Data, since it is in JavaScript.我也尝试在 HTML 中使用 ,但我不知道如何处理变量 tree.Data,因为它是在 JavaScript 中。

I am a beginner in coding.我是编码初学者。 Appreciate your help!感谢您的帮助!

 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 [dy, dx]; }); 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) { dy = 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(" + dy + "," + dx + ")"; }); 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 = dx; d.y0 = dy; }); } // 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">

Within an SVG in order to color individual words you'll need to use tspans within text elements.在 SVG 中,为了给单个单词着色,您需要在文本元素中使用 tspans。 This means searching through text elements, finding matching strings, and replacing them with new child tspan elements containing the matching word.这意味着搜索文本元素,找到匹配的字符串,并用包含匹配词的新子 tspan 元素替换它们。

Highlight (change color) of specified phrase/word in text elements :突出显示(更改颜色)文本元素中的指定短语/单词

One approach could be:一种方法可能是:

function highlight(selection,word) {
  selection.each(function() {
    this.innerHTML = this.textContent.replace(new RegExp(word, "ig"),(w)=>"<tspan>"+w+"</tspan>")
  })
}

This function takes a selection of (text) elements, and a word to find.此函数需要选择(文本)元素和要查找的单词。 It searches the text element's text content to find matching strings and replaces matching strings with a tspan containing the matching string.它搜索文本元素的文本内容以查找匹配的字符串,并用包含匹配字符串的 tspan 替换匹配的字符串。 It is case insensitive in matching text but preserves the case in the original text.它在匹配文本中不区分大小写,但保留原始文本中的大小写。

In the snippet below just type into the text box to dynamically highlight text:在下面的代码段中,只需在文本框中键入以动态突出显示文本:

 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>

Highlight with a rectangle :用矩形突出显示

We could also be a bit fancier and use a highlighter stroke, which requires adding rectangles, to do this we could use the tspans as the data for a join to create the rectangles:我们也可以更高级一点,使用需要添加矩形的荧光笔描边,为此我们可以使用 tspans 作为连接数据来创建矩形:

 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=>dx) .attr("y", d=>dy) .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>

Highlight multiple phrases/words with one highlighting style :使用一种突出显示样式突出显示多个短语/单词

If we want to highlight multiple phrases with the same color, we can modify the regex:如果我们想用相同的颜色突出显示多个短语,我们可以修改正则表达式:

  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=>dx) .attr("y", d=>dy) .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>

Highlight multiple phrases/words with different styles for each :突出显示每个具有不同样式的多个短语/单词

The challenge is a bit more difficult when dealing with multiple tspans and rectangles for different phrases.在处理不同短语的多个 tspans 和矩形时,挑战有点困难。 For this we need to modify the highlight function to match multiple strings, to allow flexibility we'll avoid hard coded classes as well.为此,我们需要修改 highlight 函数以匹配多个字符串,为了提供灵活性,我们也将避免硬编码类。 This requires a bit better data management than before, so there a few changes to the highlighting function to accommodate this.这需要比以前更好的数据管理,因此对突出显示功能进行了一些更改以适应这一点。

To do accomplish this task we'll iterate through the list of words provided and assign them colors based on specified arrays of colors for rectangle fill and text fill.为了完成这项任务,我们将遍历提供的单词列表,并根据矩形填充和文本填充的指定颜色数组为它们分配颜色。 We'll add tspans and use both the content of the tspan and the bbox of the tspan as data to pass forward to the join used to add the rectangles.我们将添加 tspan 并使用 tspan 的内容和 tspan 的 bbox 作为数据传递给用于添加矩形的连接。

For both rect and text we'll use the highlight function to give elements fills directly, eg:对于 rect 和 text,我们将使用 highlight 函数直接填充元素,例如:

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>

The above should produce:以上应产生:

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM