javascript - svg + Sprite 表 + d3 + clipPath + 位置 + 大小

标签 javascript svg d3.js sprite-sheet

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

供引用的实际 sprite 表(见下面的免责声明): Sample icons see disclaimer below

问题如下: 1) 我将 sprite 表添加到我的 html 中,硬编码 <clipPath>现在,这显示了我想要的特定 Sprite ,但是, Sprite 的尺寸/定位就像显示了整个 Sprite 表一样。我怎样才能只“捕获” Sprite 本身,而不仅仅是隐藏未使用的 Sprite ?在下图中,我想在 d3 鼠标悬停事件(第 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>

结果

Using clipPath

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

修改此示例: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");
         });

结果

Weird scaling when using <pattern>

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

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

最佳答案

我不确定 <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>

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

  1. <defs> 中定义图标元素,然后在需要时使用 <use> 引用它们元素;
  2. 使用<use>元素将图像定位在每个图标中,因此您只需定义一次图像 url、高度和宽度;
  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>

然后你像这样引用图标:

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

viewBox属性设置图像布局的内部尺寸,每次使用图标时都相同;高度和宽度可以是任何你想要的(尽管缩小当然比放大看起来更好)。如果高度/宽度比与图标不匹配,它将被压扁或拉伸(stretch),但您可以使用 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,您可能有一些数据变量告诉您​​要使用哪个图标,而不是一个类,但您明白了。

关于javascript - svg + Sprite 表 + d3 + clipPath + 位置 + 大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21193447/

相关文章:

javascript - 一页上有多个 Braintree "Hosted Fields"表单

javascript - Google 跟踪代码管理器 (GTM) 无法在 SharePoint 上运行

html - 在父 div 内缩放 svg

javascript - NVD3 调度事件不适用于 HistoricalBarChart

d3.js - d3js tree.nodes() 不是函数

javascript - React Native 的 React Navigation/Redux 实现出现错误 'undefined is not an object (evaluating ' _AppNavigator2.default.router')

javascript - Webgl 向量数组

javascript - 动态更新矩形的宽度和高度

javascript - 使用canvg将svg绘制到 Canvas 上

javascript - D3.js:在前一个转换完成之前不要开始新的转换?