【问题标题】:svg + Sprite sheet + d3 + clipPath + position + sizesvg + Sprite sheet + d3 + clipPath + position + size
【发布时间】:2014-02-07 05:29:48
【问题描述】:

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

供参考的实际精灵表(请参阅下面的免责声明):

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

修改这个例子:SO: Display CSS image sprite in SVG without using foreignObject

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>

结果

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

修改这个例子:SO: Adding an image within a circle object in 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>

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

结果

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

免责声明:这些图标不是我的作品!我仅将这些图标用于教育目的。作者的链接在这里:Fitness Icons

【问题讨论】:

标签: javascript svg d3.js sprite-sheet


【解决方案1】:

我不确定 &lt;pattern&gt; 示例发生了什么,但您的 &lt;image&gt; 元素的问题在于您没有翻译图像,因此您想要的图标位于 (0,0) 点SVG 的。

这是你需要的:

<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>

当然,如果您要制作大量图标并在多个地方使用它们,我建议:

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

此处示例: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>

然后你像这样引用图标:

<svg class="icon" viewBox="0 0 150 100" height="4em" width="6em">
        <use xlink:href="#icon3"/>
</svg>

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

现在,进入 d3。提前定义代表图标的 SVG 片段可能是最简单的,可能在单独的文件中,尽管您可以动态构建该 DOM。当你真正想要插入一个图标时,你

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

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

当然,如果您使用 d3,您可能有一些数据变量告诉您​​使用哪个图标,而不是一个类,但您明白了。

【讨论】:

  • 顺便说一下,如果您使用 SVG 作为精灵的唯一原因是因为您想使用 d3,请记住您也可以使用 d3 添加 HTML 元素和设置他们的类以触发 CSS 背景图像;甚至直接用.style()设置CSS属性。
  • 感谢您非常彻底的回答。浏览这些示例对您很有帮助。我仍然在缩放方面遇到了一些麻烦,但总的来说,我能够以我想要的大小将图标添加到 svg 画布。图标缩放的方式并不直观。人们会期望图标相对于原始图像分辨率进行缩放,但它不一定像那样工作(显然)。无论如何,您已经为我提供了足够的信息来继续学习和应用这些概念。谢谢!
  • 缩放和 SVG 需要一段时间才能习惯。请记住,绘制 SVG 的所有内容时,一个像素等于 SVG viewBox 尺寸中的一个单位。所以缩放因子是 viewBox 高度或宽度与 SVG 高度或宽度之间的比率。 (使用哪一个取决于preserveAspectRatio。)如果您的viewBox 大于图标尺寸,则图标不会填满整个SVG 大小。如果您使 viewBox 小于图标尺寸,则图标将被裁剪。字体大小示例:codepen.io/AmeliaBR/pen/iFJng
【解决方案2】:

我认为剪辑和定位图标的一种更简单的方法是使用嵌套的&lt;svg&gt; 和适当的viewBox

<svg width="100%" height="100%">
                              
    <!-- Repeat this for ever icon instance you want.
         Just change x and y attributes to set position of the icon in your SVG,
         and minX,minY (first two coords) of viewBox to select icon from sprite sheet. -->
    <svg x="0" y="0" width="150px" height="150px" viewBox="135 0 150 150">
        <image width="550px" height="420px" xlink:href="http://i.stack.imgur.com/qAO2h.png" />
    </svg>
  
</svg>

【讨论】:

    猜你喜欢
    • 2013-12-12
    • 2014-02-02
    • 2014-02-22
    • 1970-01-01
    • 2017-05-05
    • 2014-10-03
    • 2018-06-04
    • 1970-01-01
    • 2018-11-09
    相关资源
    最近更新 更多