Need to apologize in advance: for length and for my ignorance. I\'m trying to teach myself new concepts: d3.js and sprite sheets. The sprite sheet concept is simple to understan
I'm not sure what's going on with <pattern>
example, but the problem with your <image>
element is that you're not translating the image so that the icon you want is at the (0,0) point of the SVG.
This is what you need:
<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>
Of course, if you're going to be making lots of icons and using them multiple places, I would suggest:
<defs>
element, and then referencing them when needed with <use>
elements;<use>
element to position the image in each icon, so you only have to define the image url, height, and width once;<g>
element, and applying the clipping path to it, so that you only have to define the clipping path once (assuming all icons are the same size).Example here: http://codepen.io/AmeliaBR/pen/mwzBD
Key code for defining the icons:
<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>
Then you reference the icons like this:
<svg class="icon" viewBox="0 0 150 100" height="4em" width="6em">
<use xlink:href="#icon3"/>
</svg>
The viewBox
attribute sets the internal dimensions for laying out the image and will be the same every time you use the icon; the height and width can be anything you want (although scaling down will of course look better than scaling up). If the height/width ratio doesn't match the icon, it will be squished or stretched, but you can prevent that with a preserveAspectRatio
attribute.
Now, on to d3. It will probably be easiest to define the SVG fragments that represent the icons ahead of time, possibly in a separate file, although you could construct that DOM dynamically. When you actually want to insert an icon, you
For example, to add an inline icon image at the end of every element with the class "warning", you would do something like this:
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");
Of course, if you're using d3, you've probably got some data variable that tells you which icon to use, instead of a class, but you get the idea.
I think a much simpler way to clip and position the icon is by using a nested <svg>
with an appropriate 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>