2015-07-01 6 views
3

Я создал график с d3, чтобы показать дефекты на поверхности. Сама поверхность имеет ширину около 1000 мм, но может составлять несколько километров. Чтобы увидеть дефекты более четко, я реализовал масштабирование d3, но иногда дефекты распространяются по диапазону x, поэтому масштабирование в этом случае приведет к прокрутке слева направо.Масштабирование или масштабирование с помощью d3.js

Вот упрощенный jsFiddle

Я, однако, может изменить масштаб просмотра конкретного дефекта, скажем, один начинается 1000мм и заканчивается в 1500мм я мог бы сделать:

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

Но так как мои дефекты являются прямоугольниками Мне нужно вычислить ширину с yScale так:

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

Который не будет работать, если я изменил домен весов (высота может быть меньше, чем значение домена, давая отрицательные значения).

Так как я могу решить эту проблему? Есть ли способ вычислить высоту дефекта относительно yScale. Или есть еще одна возможность масштабирования?

UPDATE После Marks предложения я реализовал его и сделал второй jsFiddle

Проблема я столкнулся сейчас также с весами. Я попытался исправить это немного, но как только вы используете панорамирование или масштабирование, функции масштабирования (xScale и yScale) не будут давать правильные значения (в основном отрицательные, поскольку они не отображаются в окне просмотра).

.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);       
}); 

Таким образом, без панорамирования или масштабирования и непосредственного нажатия вышеуказанный код работает. Может ли кто-нибудь дать мне понять, что я сделал не так?

+0

Звуки для меня, как вы хотите реализовать [зум дезертировать] (http://bl.ocks.org/mbostock/9656675) ... – Mark

+0

@Mark Я обновил мой вопрос –

ответ

0

Хорошо, я понял. Вы можете масштабировать и переводить с помощью функции масштабирования. Хорошим примером является zoom to bounding box example, но этот пример основан на d3.geo без функций масштабирования x и y.

С х и у lineair масштабируется объектов вы можете сделать это:

.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);       
}); 

Во-первых, вы должны сбросить переводить и масштаб, прежде чем делать какие-либо XScale и расчеты yScale. Я просто делаю это следующим образом:

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

dx и dy - это ширина/высота объекта. Чтобы добраться до середины объекта, нужно взять масштабированное значение x и y и добавить к нему половину ширины и высоты. Иначе он не будет центрировать должным образом (я говорю, конечно, потому что я возился с ним).

Масштаб рассчитывается путем достижения максимальной ширины или высоты объекта и деления его на 0,85, чтобы получить небольшое поле вокруг него.

Вот jsFiddle

Смежные вопросы