1

I wanted to create a circular crop an image to use in conjunction with a svg circle, and decided on filling the svg circle with a pattern. I have it working for the single case:

defs.append("svg:pattern")
    .attr("id", "story1")
    .attr("width", 200)
    .attr("height", 100)
    .attr("patternUnits", "userSpaceOnUse")
    .append("svg:image")
    .attr("xlink:href", 'ml-image4.png')
    .attr("width", 200)
    .attr("height", 100)
    .attr('x',0)
    .attr('y',0);

var circle1 = svg.append("circle")
        .attr("cx", 100)
        .attr("cy", 50)
        .attr("r", 40)
        .style("fill", "#fff")
        .style("fill", "url(#story1)")
        .style('stroke','#000')
        .style('stroke-width', 5);

Then I got all gung-ho and tried to adapt for a programmatic implementation, but it didn't pan out so well. I'm hoping there is a way to do it, because my end goal is to have an application that uses many pictures as patterns. It will be like a little gallery where each svg circle is spaced out across the page using .attr('x', function(d,i) { return 100+i*200})) and each circle referencing a different pattern. The pattern id is a data member, so I was trying to do this: .style('fill',function(d) {return "url(#"+d.id+")"; }). I'm not exactly sure why it didn't work; to my eyes it seems functional-ish. I did get the error:

Uncaught DOMException: Failed to execute 'querySelectorAll' on 'Element': 'svg:pattern' is not a valid selector.

Here is my adaptation for programmatic def patterns and a quick look at my data:

var data = [
    {'id':'story1', 'Title':'Title1', 'Date':'03/10/2017','Icon':'Icon1.png', 'Link':'www.link1.com/'},
    {'id':'story2', 'Title':'Title2', 'Date':'12/15/2017','Icon':'Icon2.png', 'Link':'www.link2.com/'}
];

var defs = svg.append('svg:defs');

defs.selectAll(null)
    .data(data)
    .enter()
    .append('svg:pattern')
    .attr('id',function(d) {return d.id; })
    .attr('width', 200)
    .attr('height', 100)
    .attr('patternUnits', 'userSpaceOnUse')
    .append('svg:image')
    .attr('xlink:href', function(d) {return d.Icon})
    .attr('width', 200)
    .attr('height', 100)
    .attr('x',0)
    .attr('y',0);

svg.selectAll('circle')
    .data(data)
    .enter()
    .append('circle')
    .attr('cx', function(d,i) {return 100+i*200})
    .attr('cy', 50)
    .attr('r',40)
    .style('fill',function(d) {return "url(#"+d.id+")"; })
    .style('stroke','#000')
    .style('stroke-width',3);

Question

Judging by the error, my adaptation seems to be flawed. What can I tweak to get programmatic patterns for svg circles here? In my humble opinion, my approach isn't all that different from the simple case at the very beginning of the post (1 pattern 1 circle), all I was trying to do was scale it up so I can use d3.selectAll() using my data.

Arash Howaida
  • 2,575
  • 2
  • 19
  • 50
  • Drop that namespace: `defs.selectAll('pattern')`. Even better: `defs.selectAll(null)`. The rest seems to be ok and should work, just as I did here: https://stackoverflow.com/a/41320142/5768908. – Gerardo Furtado Sep 03 '18 at 12:38
  • @GerardoFurtado Great idea, that got it kind of working, I made updates to the post for `defs.selectAll(null)`. The only thing now is the image fill is the same for each circle. Not sure why this is still being read as static; I'm experimenting with it now. – Arash Howaida Sep 03 '18 at 13:00
  • @GerardoFurtado Never mind, got it! thanks for pointing me in the right direction! – Arash Howaida Sep 03 '18 at 13:15

0 Answers0