SVG文本颜色与背景对应

时间:2015-03-26 07:43:26

标签: html css svg d3.js

我正在使用D3.js制作一张如下图所示的图表:

enter image description here

一般来说,一切正常,但我不知道如果标签没有覆盖所有标签,如何使标签可见。我的第一个想法是添加两个标签。一个是白色,另一个是酒吧颜色。我希望可能会发生一些魔法,并且栏外的文字将是绿色的,这是行不通的。

以下是我用来添加标签的代码:

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");

如何达到这样的效果?

3 个答案:

答案 0 :(得分:2)

使用剪辑路径的方法已经被squeamish ossifrage的answer所描述。我已经整理了一个工作片段d3方式:

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");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

我通过不在clipPath部分设置defs,而是链接到已通过rect绘制的xlink:href来进一步缩短内容:< / p>

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>

答案 1 :(得分:1)

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

  

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

所以,这只是在CSS中设置它的问题:

yourSelector {
    mix-blend-mode: someValue;
}

这是一个演示:

&#13;
&#13;
text {
	mix-blend-mode: difference;
}
&#13;
<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>
&#13;
&#13;
&#13;

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

答案 2 :(得分:0)

使用剪贴蒙版可以很容易地做到这一点。这是一个静态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代码中应该不会太难。