【问题标题】:SVG text color with correspond to background与背景对应的 SVG 文本颜色
【发布时间】:2021-06-03 01:18:39
【问题描述】:

我正在使用 D3.js 在此图像上制作图表:

一般来说,一切正常,但我不知道如何在栏没有覆盖所有标签时使标签可见。我的第一个想法是添加两个标签。一个是白色的,另一个是条形的。我希望能发生一些神奇的事情,让栏外的文字变成绿色,但这是行不通的。

这是我用来添加标签的一段代码:

var rect = this.svg.selectAll("text")
                .data(dataset, dataset.key)
                .enter();

rect.append("text")
  .text(function(d) { return d.value; })
  .attr("text-anchor", "end")
  .attr("x", w-10) 
  .attr("y", function(d, i) { return graph.xScale(i) + graph.xScale(1)/2; })
  .attr("fill", color)
  .attr("class", "value");

rect.append("text")
  .text(function(d) { return d.key; })
  .attr("text-anchor", "start")
  .attr("x", 10) 
  .attr("y", function(d, i) { return graph.xScale(i) + graph.xScale(1)/2; })
  .attr("fill", color)
  .attr("class", "key");

rect.append("text")
  .text(function(d) { return d.key; })
  .attr("text-anchor", "start")
  .attr("x", 10) 
  .attr("y", function(d, i) { return graph.xScale(i) + graph.xScale(1)/2; })
  .attr("fill", textColor)
  .attr("class", "keybg");

如何达到这样的效果?

【问题讨论】:

  • 我猜没有 CSS 可以反转文本部分的颜色,它从矩形中突出来。也许您想以某种方式更改颜色,使文本在条形颜色和背景颜色上都可读。或者检测一个突出的标签并将其完全移到外面并赋予它另一种颜色。

标签: html css svg d3.js


【解决方案1】:

实际上,这只能使用 CSS 来完成。有一个名为 mix-blend-mode 的 CSS 属性,

...描述元素的内容应该如何与元素的直接父元素的内容和元素的背景混合。

所以,只需在 CSS 中设置即可:

yourSelector {
    mix-blend-mode: someValue;
}

这是一个演示:

text {
	mix-blend-mode: difference;
}
<svg width="400" heigth="200">
	<rect x="10" y="10" height="30" width="350" fill="green"></rect>
	<rect x="10" y="50" height="30" width="150" fill="green"></rect>
	<rect x="10" y="90" height="30" width="50" fill="green"></rect>
	<text x="20" y="30" fill="white">I am a very very very very long long long long long text</text>
	<text x="20" y="70" fill="white">I am a very very very very long long long long long text</text>
	<text x="20" y="110" fill="white">I am a very very very very long long long long long text</text>
</svg>

有两个问题:不能精确控制颜色,IE/Edge不支持。

【讨论】:

    【解决方案2】:

    squeamish ossifrage 的answer 已经描述了使用剪辑路径的方法。我已经以 d3 的方式组装了一个可以工作的 sn-p:

    var svg = d3.select("body")
        .append("svg")
        .attr({
            width: 400,
            height: 400
        });
    
    var textOut = svg.append("text")
        .attr({
            x: 120,
            y: 66
        })
        .style({
            fill: "black",
            stroke: "none"
        })
        .text("Description");
    
    var rect = svg.append("rect")
                        .attr({
                            id: "rect",
                            x: 50,
                            y: 50,
                            width: 100,
                            height: 20
                        })
                        .style({
                            fill: "limegreen",
                            stroke: "darkgreen"
                        });
    
    svg.append("clipPath")
        .attr("id", "clip")
        .append("use")
        .attr("xlink:href", "#rect");
    
    var textIn = svg.append("text")
        .attr({
            x: 120,
            y: 66
        })
        .style({
            fill: "white",
            stroke: "none",
            "clip-path": "url(#clip)"
        })
        .text("Description");
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"&gt;&lt;/script&gt;

    我没有在defs 部分设置clipPaths,而是链接到已经通过xlink:href 绘制的rect,从而进一步缩短了时间:

    svg.append("clipPath")
        .attr("id", "clip")
        .append("use")
        .attr("xlink:href", "#rect");
    

    这将产生如下所示的 svg 结构:

      <text x="120" y="66" style="fill: rgb(0, 0, 0); stroke: none;">Description</text>
      <rect id="rect" x="50" y="50" width="100" height="20" style="fill: rgb(50, 205, 50); stroke: rgb(0, 100, 0);"/>
      <clipPath id="clip">
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#rect"/>
      </clipPath>
      <text x="120" y="66" style="fill: rgb(255, 255, 255); stroke: none; clip-path: url(#clip);">Description</text>
    

    【讨论】:

    • 谢谢你们两位,这非常有帮助。我希望最后一个问题,当我动态改变矩形的宽度时,这个 clipPath-> 使用 xlink:href 将如何起作用?
    • xlink:href 是一个实时链接,可在调整 rect 大小时调整剪辑路径。尝试在 sn-p 末尾添加rect.transition().attr({ width: 20 }).transition().attr({ width: 100 }); 以查看矩形的动画。
    【解决方案3】:

    使用剪贴蒙版可以很容易地做到这一点。这是一个静态 SVG 来说明这一点:

    <svg width="400" height="200" viewBox="0 0 400 200">
      <defs>
        <clipPath id="clip_1">
          <rect width="50" height="38" />
        </clipPath>
        <clipPath id="clip_2">
          <rect width="100" height="38" />
        </clipPath>
        <clipPath id="clip_3">
          <rect width="150" height="38" />
        </clipPath>
        <clipPath id="clip_4">
          <rect width="250" height="38" />
        </clipPath>
        <clipPath id="clip_5">
          <rect width="300" height="38" />
        </clipPath>
      </defs>
      <rect width="400" height="200" fill="white" path="none" />
      <g transform="translate(0,1)">
        <text x="10" y="28" font-family="Verdana" font-size="20" fill="red">Lorem ipsum dolor sit amet</text>
        <g clip-path="url(#clip_1)">
          <rect width="50" height="38" fill="red" />
          <text x="10" y="28" font-family="Verdana" font-size="20" fill="white">Lorem ipsum dolor sit amet</text>
        </g>
      </g>
      <g transform="translate(0,41)">
        <text x="10" y="28" font-family="Verdana" font-size="20" fill="orange">Consectetur adipiscing elit</text>
        <g clip-path="url(#clip_2)">
          <rect width="100" height="38" fill="orange" />
          <text x="10" y="28" font-family="Verdana" font-size="20" fill="white">Consectetur adipiscing elit</text>
        </g>
      </g>
      <g transform="translate(0,81)">
        <text x="10" y="28" font-family="Verdana" font-size="20" fill="green">Proin egestas suscipit justo</text>
        <g clip-path="url(#clip_3)">
          <rect width="150" height="38" fill="green" />
          <text x="10" y="28" font-family="Verdana" font-size="20" fill="white">Proin egestas suscipit justo</text>
        </g>
      </g>
      <g transform="translate(0,121)">
        <text x="10" y="28" font-family="Verdana" font-size="20" fill="blue">Nam eget magna gravida eros</text>
        <g clip-path="url(#clip_4)">
          <rect width="250" height="38" fill="blue" />
          <text x="10" y="28" font-family="Verdana" font-size="20" fill="white">Nam eget magna gravida eros</text>
        </g>
      </g>
      <g transform="translate(0,161)">
        <text x="10" y="28" font-family="Verdana" font-size="20" fill="purple">Accumsan tempor eget sed augue</text>
        <g clip-path="url(#clip_5)">
          <rect width="300" height="38" fill="purple" />
          <text x="10" y="28" font-family="Verdana" font-size="20" fill="white">Accumsan tempor eget sed augue</text>
        </g>
      </g>
    </svg>

    基本上,您需要用两种不同的颜色绘制每个文本段,并使用剪贴蒙版显示位于背景上的文本。因此,例如,此示例中的第一个柱创建如下:

    1:定义与前景对象形状完全匹配的剪辑路径:

    <defs>
      <clipPath id="clip_1">
        <rect width="50" height="38" />
      </clipPath>
      <!-- more paths here -->
    </defs>
    

    2:根据背景颜色绘制要查看的文本:

    <text x="10" y="28" font-family="Verdana" font-size="20" fill="red">Lorem ipsum dolor sit amet</text>
    

    3:使用与剪辑路径和背景文本相同的坐标创建包含前景对象和文本的组,并包含clip-path 参数以裁剪超出前景对象的文本:

    <g clip-path="url(#clip_1)">
      <rect width="50" height="38" fill="red" />
      <text x="10" y="28" font-family="Verdana" font-size="20" fill="white">Lorem ipsum dolor sit amet</text>
    </g>
    

    将它集成到您​​的 D3 代码中应该不会太难。

    【讨论】:

      猜你喜欢
      • 2015-09-09
      • 2021-12-04
      • 1970-01-01
      相关资源
      最近更新 更多