svg + Sprite sheet + d3 + clipPath + position + size

Jam*_*mes 7 javascript svg sprite-sheet d3.js

需要提前道歉:长度和我的无知.我正在尝试自学新概念:d3.js和精灵表.精灵表概念很容易理解,但我很困惑如何将它整合到d3中.基本上我想要做的是从精灵表中选择我想用作图像的精灵,然后使用d3在页面上的其他地方显示这个选定的精灵,并且很可能是同一精灵的多个副本.

实际的精灵表供参考(见下文免责声明): 示例图标请参阅以下免责声明

以下是问题:1)我将精灵表添加到我的html中,硬编码<clipPath>现在,这显示了我想要的特定精灵,但是,精灵的尺寸/位置就像显示整个精灵表一样.我怎样才能"捕捉"精灵本身,而不仅仅是隐藏未使用的精灵?在下图中,我想在d3鼠标悬停事件中使用单个"图标"(第2部分).

修改此示例:SO:在不使用foreignObject的情况下在SVG中显示CSS图像精灵

HTML

<svg id="mySvg1" width="100%" height="100%">
    <defs>
        <clipPath id="c">
            <rect x="135" y="0" width="150" height="150"/>
        </clipPath>
    </defs>
        <image transform="scale(1.0)" x="0" y="0" width="550" height="420" xlink:href="static/img/iconSheet.png" clip-path="url(#c)"/>
<svg>
Run Code Online (Sandbox Code Playgroud)

结果

使用clipPath

2)我可以<pattern>用来确定要在d3对象/事件中显示的图像.就像在矩形中显示图形一样.但这似乎不适用于大型图像(精灵表)?如果我尝试使用精灵表本身及其在模式中的原生尺寸,它会变得奇怪和模糊.如果我们解决第1部分,我们可能会忽略第2部分,但是对于一般知识/将来的使用,这将是很好的理解.

修改此示例:SO:在d3 javascript中在圆形对象中添加图像?

HTML

<svg id="mySvg" width="550" height="420">
  <defs id="mdef">
    <pattern id="image" x="0" y="0" height="550" width="420">
      <image transform="scale(1.0)" x="0" y="0" width="550" height="420" xlink:href="static/img/iconSheet.png"></image>
    </pattern>
  </defs>
</svg>
Run Code Online (Sandbox Code Playgroud)

使用Javascript:

var svgContainer = d3.select("div#content-main").append("svg")
                                    .attr("width", 740)
                                    .attr("height", 760)
                                    .attr("class", "mySvg")
                                    .style("border", "none");

svgContainer.append("rect")
         .attr("class", "logo")
         .attr("x", 0)
         .attr("y", 0)
         .attr("width", 550)
         .attr("height", 420)
         .style("fill", "transparent")  
         .style("stroke", "black")     
         .style("stroke-width", 0.25)     
         .on("mouseover", function(){ 
               d3.select(this)
                   .style("fill", "url(#image)");
         })
          .on("mouseout", function(){ 
               d3.select(this)
                   .style("fill", "transparent");
         });
Run Code Online (Sandbox Code Playgroud)

结果

使用<pattern>时出现奇怪的缩放

3)如果有更有效的方法来实现这一点,我愿意接受建议.我只是坚持使用d3模型,因为我已经渲染了一个svg对象,我只需要添加它.

免责声明:图标不是我的作品!我使用这些图标仅用于教育目的.作者的链接在这里:健身图标

Ame*_*aBR 8

我不确定<pattern>示例中发生了什么,但你的<image>元素的问题是你没有翻译图像,所以你想要的图标位于SVG的(0,0)点.

这就是你需要的:

<svg id="mySvg1" width="100%" height="100%" viewBox="0 0 150 150">
    <defs>
        <clipPath id="c">
            <rect x="135" y="0" width="150" height="150"/>
        </clipPath>
    </defs>
        <image transform="translate(-135,0)" width="550" height="420" 
            xlink:href="static/img/iconSheet.png" clip-path="url(#c)"/>
<svg>
Run Code Online (Sandbox Code Playgroud)

当然,如果您要制作大量图标并将它们用于多个位置,我建议:

  1. 定义<defs>元素中的图标,然后在需要时使用<use>元素引用它们;
  2. 使用<use>元素在每个图标中定位图像,因此您只需要定义图像的网址,高度和宽度一次;
  3. 将每个图像/使用元素嵌套在<g>元素中,并将剪切路径应用于它,这样您只需定义剪切路径一次(假设所有图标大小相同).

例如:http://codepen.io/AmeliaBR/pen/mwzBD

用于定义图标的关键代码:

<svg class="icon-defs">
  <defs>
    <!-- The icons are defined in an SVG <defs> element;
        it could be in a different file,
        since the icons will be referenced by url. -->

    <!-- One clipping path defines icon size -->
    <clipPath id="icon-cp" >
        <rect x="0" y="0" width="150" height="100" />
    </clipPath>

    <!-- One image element imports the file -->
    <image id="icon-sprite" width="969" height="293" 
           xlink:href="http://i.stack.imgur.com/TPx5h.png" />

    <!-- Each icon fragment uses the same image 
         with a different translation -->
    <g id="icon1" clip-path="url(#icon-cp)">
        <use xlink:href="#icon-sprite" 
            transform="translate(0,0)" />
    </g>
    <g id="icon2" clip-path="url(#icon-cp)">
        <use xlink:href="#icon-sprite" 
            transform="translate(-240,0)" />
    </g>
    <g id="icon3" clip-path="url(#icon-cp)">
        <use xlink:href="#icon-sprite" 
            transform="translate(-240,-193)" />
    </g>   
 </defs>
Run Code Online (Sandbox Code Playgroud)

然后你引用这样的图标:

<svg class="icon" viewBox="0 0 150 100" height="4em" width="6em">
        <use xlink:href="#icon3"/>
</svg>
Run Code Online (Sandbox Code Playgroud)

viewBox属性设置布局图像的内部尺寸,每次使用图标时都相同; 高度和宽度可以是你想要的任何东西(虽然缩小当然看起来比放大更好).如果高度/宽度比率与图标不匹配,则会被压缩或拉伸,但您可以使用preserveAspectRatio属性来阻止它.

现在,到d3.虽然您可以动态地构造该DOM,但可能最容易定义提前表示图标的SVG片段,可能在单独的文件中.当你真的想要插入一个图标时,你

例如,要在每个元素的末尾添加带有"警告"类的内联图标图像,您可以执行以下操作:

d3.selectAll(".warning")
    .append("svg")
      .attr("viewBox", "0 0 "+ iconWidth + " " + iconHeight)
      .style("display", "inline")
      .style("height", "1em")
      .style("width", (iconWidth/iconHeight) + "em")
    .append("use")
      .attr("xlink:href", "#warning");
Run Code Online (Sandbox Code Playgroud)

当然,如果你正在使用d3,你可能会得到一些数据变量来告诉你使用哪个图标而不是类,但你明白了.

  • 顺便说一句,如果你只是因为想要使用d3而使用SVG的***因为你想使用d3,请记住你也可以使用d3添加HTML元素并设置它们的类以触发CSS背景图像; 甚至直接用`.style()`设置CSS属性. (3认同)