Scaling or scaling with d3.js

I created a graph with d3 to show surface defects. The surface itself is about 1000 mm wide, but can be several kilometers. To see the defects more clearly, I implemented d3 scaling, but sometimes the defects extend over the x-range, so scaling in this case will result in scrolling from left to right.

Here's a simplified jsFiddle

I could change the scale to see a specific defect, say one starts at 1000mm and ends at 1500mm, I could do:

var yScale = d3.scale.linear() 
     .domain([1000 - margin, 1500 + margin])
     .range([0, pixelHeight]);   

      

But since my defects are rectangles, I need to calculate the width using yScale like this:

.attr("height", function (d) {
        return yScale(d.height);
    })

      

Which won't work if I change the scale domain (the height can be less than the domain value, giving negative values).

So how can I solve this problem? Is there a way to calculate the height of the defect relative to yScale. Or is there another scalability option?

UPDATE Following Marks suggestion, I implemented it and made a second jsFiddle

The problem I am currently facing is also related to scale. I tried to fix this a bit, but once you pan or zoom the zoom functions (xScale and yScale) won't give the correct values ​​(mostly negative because it's from the viewport).

.on('click', function (d) {
    d3.selectAll('rect').classed('selected-rect', false);
    d3.select(this).classed('selected-rect', true);

    var dx = xScale(d.width)*2.2,
        dy = yScale(d.height)*2.2,
        x = xScale(d.x) ,
        y = yScale(d.y) ,
        scale = .9 / Math.max(dx / width, dy / pixelHeight),
      translate = [pixelWidth / 2 - (scale*1.033) * x, 
                   pixelHeight / 2 - (scale*1.033) * y];

    svg.transition()
        .duration(750)
        .call(zoom.translate(translate).scale(scale).event);                           
});

      

So, without panning or zooming and clicking directly, the above code works. Can anyone give me an idea of ​​what I did wrong?

+3


source to share


1 answer


Ok I figured it out. You can scale and translate using the zoom function. Scaling to a bounding rectangular example is a good example , but this example is based on d3.geo without the x and y scaling functions.

With scaled objects x and y, you can do this:

.on('click', function (d) {
    d3.selectAll('rect').classed('selected-rect', false);
    d3.select(this).classed('selected-rect', true);

    zoom.translate([0, 0]).scale(1).event;   

    var dx = xScale(d.width),
        dy = yScale(d.height),
        x = xScale(d.x) + xScale(d.width/2),
        y = yScale(d.y) + yScale(d.height/2),
        scale = .85 / Math.max(dx / pixelWidth, dy / pixelHeight),
      translate = [pixelWidth / 2 - scale * x, 
                   pixelHeight / 2 - scale * y];

    svg.transition()
        .duration(750)
        .call(zoom.translate(translate).scale(scale).event);                           
});

      

First of all, you must reset translate and scale before doing any xScale and yScale calculations. I just do it with this statement:



zoom.translate([0, 0]).scale(1).event; 

      

dx and dy - scaled width / height of objects. To get to the middle of the object, you need to take the scaled x and y value and add half the width and height to it. Otherwise it won't center properly (I say, of course, because I fiddled with it).

The scale is calculated by assuming the maximum width or height of the object, and the device has 0.85 divided by it to get a small margin around it.

Here's the jsFiddle

0


source







All Articles