I don't think I appropriately used groups but I think the key is having the transform then translate thing in there.

So my example is

But because I didn't use groups properly I don't know that the icons would handle zooming like you seem to want. In my example I just append the images to the circles I've created.

  .attr("transform", function(d) { return "translate(" + projection(d.geometry.coordinates) + ")"; })
  .attr('fill', '#fad959')


There a few issues here. First, I'm not sure you fully grasp how d3 selections works, as indicated by the fact that you are binding amenities.features to your selection and then accessing it for the x and y attributes via an index. See How Selections Work for more details on this. In addition, you need to translate the geographic coordinates of the features to screen coordinates by passing them through your geographic projection function. This should get you close:

// more projections:
var projection = d3.geoAlbers();

var amenities = svg.selectAll('.amenities')

    .attr("class", "amenities")     
    .attr("xlink:href", "maki/renders/post-18@2x.png")
    // The data is already bound so use it instead of the index. Als, 
    // you need to translate geo coordinates to screen coordinates by 
    // passing them through your projection function.
    .attr("x", function(d,i) {return projection(d.geometry.coordinates)[0];})
    .attr("y", function(d,i) {return projection(d.geometry.coordinates)[1];})
    .attr("width", "20")
    .attr("height", "20")

Related Query