D3 Перемещение трансфокатора

Мне было интересно, можете ли вы помочь мне с последующими функциями D3js Zoom и pan в следующем скрипте: http://jsfiddle.net/moosejaw/nUF6X/5/

Я надеюсь, что код (хотя и не большой) прост.

У меня есть диаграмма, которая имеет общую длину хромосомы по общей длине хромосомы. Значения тика представляют собой индивидуальные длины (итоговые значения) каждой хромосомы. Тики отформатированы как имя хромосом (чтобы выглядеть красиво для конечного пользователя).

У меня возникают следующие проблемы:

  • Знаки оси x и оси Y выходят за пределы области графика. Когда я не укажу значения тика явно, метки "исчезают", как должны. См:

    var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")
    .tickValues(tickValues)
    .tickFormat(function(d) { 
        var ret = bpToChrMBP(d);
        return ret.chr;
    });
    
  • Как предотвратить, чтобы ось x не панорамировалась слева до минимального значения? Также не панорамирование вправо от максимального значения? Это случается, если я увеличен. (То же самое для оси Y, кроме верхнего и нижнего).

  • Есть ли способ "центрировать" метки меток между отметками меток. Маркеры не равномерно распределены. Я попытался использовать subdivide для небольших меток, но это не делит между отметками правильно.

Любая помощь будет принята с благодарностью!

Matt

Ответ 1

Этот скрипт решает большинство ваших проблем: http://jsfiddle.net/CtTkP/ Ниже приведены пояснения:

  • Я не уверен, что вы имели ввиду, выходя за пределы области графиков. Должны ли метки накладываться на chart-area? Если вы имеете в виду, что при панорамировании метки выходят за пределы оси, проблема может быть решена с использованием еще двух clip-path разумно, хотя это не позволяет грациозно затухать значения, которые обеспечивают переводы svg.axis:
var clipX = svg.append("clipPath")
      .attr('id', 'clip-x-axis')
      .append('rect')
      .attr('x', 0)
      .attr('y', 0)
      .attr('width', width)
      .attr('height', margin.bottom);

svg.append("g")
    .attr("class", "x axis")
    .attr('clip-path', 'url(#clip-x-axis)')
    .attr("transform", "translate(0, " + height + ")")
    .call(xAxis);

// ...

var clipY = svg.append("clipPath")
      .attr('id', 'clip-y-axis')
      .append('rect')
      .attr('x', - margin.left)
      .attr('y', 0)
      .attr('height', height)
      .attr('width', margin.left);

svg.append("g")
    .attr("class", "y axis")
    .attr('clip-path', 'url(#clip-y-axis)')
    .call(yAxis);
  • Чтобы предотвратить панорамирование, выходящее за пределы значений, вам необходимо вручную ограничить translate для увеличения:
function zoomed() {

     var trans = zoom.translate(),
         scale = zoom.scale();

     tx = Math.min(0, Math.max(width * (1 - scale), trans[0]));
     ty = Math.min(0, Math.max(height * (1 - scale), trans[1]));

     zoom.translate([tx, ty]);

    svg.select(".x.axis").call(xAxis);
    svg.select(".y.axis").call(yAxis);

    // ...

Это не позволит графику панорамировать за пределы.

  • Поскольку вы явно переопределяете tickValues, вы можете настроить значения, чтобы центрировать их:
var tickValues2 = [];
tickValues.forEach(function (t, idx) {
    if (idx < tickValues.length - 1) {
        tickValues2.push((t + tickValues[idx + 1]) / 2);
    }
});

Затем вместо tickValues для xAxis и yAxis используйте tickValues2.

Ответ 2

  • Проблема заключается в том, что вы устанавливаете tickValues вручную, вместо того чтобы позволить шкале x и y делать это за вас. Попробуйте прокомментировать это: // .tickValues(tickValues)

    var x = d3.scale.linear(). rangeRound ([0, width]). domain (d3.extent(tickValues));

    var xAxis = d3.svg.axis()     .scale(х)     .orient( "дно" )     //.tickValues ​​(tickValues)     .tickFormat(function (d) {         var ret = bpToChrMBP (d);         return ret.chr;     });

Быстрое и грязное исправление, позволяющее явно задавать значения tickValues, может заключаться в определении отсечения для каждой оси.

Вам также не нужна функция make_x_axis (такая же для оси y). Посмотрите этот масштабируемый пример диаграммы рассеяния: http://bl.ocks.org/ameliagreenhall/raw/d30a9ceb68f5b0fc903c/

  • Чтобы предотвратить панорамирование влево/вправо после отсечки, вам придется повторно реализовать d3.behavior.zoom(). Прямо сейчас есть функция под названием mousemove, которая вызывает translateTo, и эта функция не имеет предел:

    Функция translateTo (p, l) { l = точка (l); перевести [0] + = p [0] - l [0]; перевести [1] + = p [1] - l [1]; }

  • Вы можете попробовать играть с атрибутами dx и dy при определении осей.