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

标签 javascript html jquery css d3.js

我使用此代码制作了 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>

上面应该产生:

enter image description here

关于Javascript 在文本中查找单词并动态改变颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68485651/

相关文章:

javascript - 将数据从 mongodb 传递到 ejs

javascript - 使用 webpack (Babel/ES6) 导入 moment-timzone 和 moment-range

javascript - 使用 javascript 将 yaml 转换为 json

javascript - 使用媒体查询后是否可以更改 html?

javascript - 如何在 Javascript 中获取前一个 DOM 元素?

jquery - 如何使用 jQuery 查找具有特定值的选项标签

javascript - 通过表单提交下载文件,失败时需要回调

javascript - 了解 Node.js 中的简单流转换

html - 下拉菜单出现在 div 之外的其他内容后面

jquery - jqplot 突出显示堆积柱形图