d3.js svg image: scale from center of rectangle

d3.js, javascript, scaling, svg

Solution

Set up: A 50 x 50 box at 200, 200. It needs to transition to a 100 x 100. It is 50 larger and wider, so needs to move back and up 25, eg 175, 175. Replace hard coded values with functions that look up the current width on mouse hover to calculate the exact values.

d3.select('svg').append('rect');
rect = d3.select('rect');
rect.attr({
    height: 50,
    width: 50,
    x: 200,
    y: 200,
    color: 'steelblue'
})
.transition()
.attr({
    width: 100,
    height: 100,
    x: 175,
    y: 175
});

Problem

I'm using d3 to populate a cartesian plane with a bunch of `svg:image` elements spread out over different coordinates. I'd like to add `mouserover` and `mouseout` logic that zooms the image the mouse is over in and lightens the opacity of the others. I'm filtering my selection on mouseover to only select the desired element and everything is working great, except my scaling logic doesn't seem to get the desired effect. The images expand downward and to the right rather than in the outward from the diagonal center. Here's what I've tried: - `transform: scale(1.5)` Which expands, but also totally shifts the image's position - `transform: translate(-(width/2), -(height/2))` combined with scale, which does the same but from a different starting position - Changing the x and y coords to ones adjusted for half widths and heights, which has the same effect. Is there no `text-anchor` equivalent for image elements with which I could set an "anchor point" to scale from? I'm not sure what the html svg parlance is, but I guess I'm thinking of something similar to the anchor points a lot of vector editors have. Current approach, mouseover handler: ``` function fade(dir){ return function(d){ var others = svg.selectAll("image.movie_cover") .filter(function(g,i){ return g != d }) .transition().duration(800) .style("opacity",.3); var single = svg.selectAll("image.movie_cover") .filter(function(g,i){ return g === d; }) .transition().duration(900) .attr("transform", "translate(-40,-40) scale(1.4)") var title = keys[coords.indexOf(d)]; var url = "/static/eshk/"+hash+"_images/" + title + ".jpg"; tt.transition() .duration(200) .style("opacity", .9); tt.html(title) .style("left", (d3.event.pageX) + "px") .style("top", (d3.event.pageY - 28) + "px"); } } ``` Using this method, the images move inconsistent distances despite all being the same size.

Original source