【问题标题】:Javascript find a word in text and change color dynamicallyJavascript 在文本中查找单词并动态更改颜色
【发布时间】:2021-09-29 18:47:08
【问题描述】:

我用这段代码bl.ocks.org/d3noob/8375092做了一个d3.js图表​​

我正在尝试更改单词的颜色。在每个单词的实例中,我都希望改变颜色。例如,如果您查看图表,有 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">

【问题讨论】:

  • 关于您的 CSS 尝试,CSS“颜色”属性不适用于 SVG 文本,这就是您检查并查看样式但颜色没有改变的原因。它是适用于 SVG 文本的“填充”属性。
  • 提供更多代码。我的意思是我可以看到的所有可能的代码以及您如何检查它们的屏幕截图
  • 1.使用 FILL 属性而不是 COLOR,2. 为了突出显示单词,请阅读@AndrewReid 答案。

标签: javascript html jquery css d3.js


【解决方案1】:

在 SVG 中,为了给单个单词着色,您需要在文本元素中使用 tspan。这意味着搜索文本元素,找到匹配的字符串,然后用包含匹配词的新子 tspan 元素替换它们。

在文本元素中突出显示(更改颜色)指定短语/单词

一种方法可能是:

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

这个函数需要选择(文本)元素和要查找的单词。它搜索文本元素的文本内容以查找匹配字符串,并用包含匹配字符串的 tspan 替换匹配字符串。它在匹配文本时不区分大小写,但在原始文本中保留大小写。

在下面的 sn-p 中,只需在文本框中键入即可动态突出显示文本:

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 和矩形时,挑战有点困难。为此,我们需要修改 highlight 函数以匹配多个字符串,以提供灵活性,我们也将避免硬编码类。这需要比以前更好的数据管理,因此对突出显示功能进行了一些更改以适应这一点。

为了完成这项任务,我们将遍历提供的单词列表,并根据指定的颜色数组为它们分配颜色,用于矩形填充和文本填充。我们将添加 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>

以上应产生:

【讨论】:

  • 感谢@AndrewReid 的帮助!感谢所有帮助编辑我的问题并解释填充与颜色属性的人。我将努力将这些更改整合到我的项目中,并让你知道它是如何进行的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-22
  • 1970-01-01
  • 2014-04-28
  • 2021-05-30
  • 1970-01-01
  • 2017-10-25
  • 1970-01-01
相关资源
最近更新 更多