Выборочный зум D3

Я работаю над компоновкой принудительного графа с некоторыми дополнительными функциями: выбираемые ссылки/узлы, всплывающие подсказки, эффект «рыбий глаз» и, что важно для моего вопроса, масштабирование и панорамирование.

Теперь масштабирование работает очень хорошо:

d3 ... .append('svg:g').call(d3.behavior.zoom().on("zoom", redraw))... 

Где функция перерисовки выглядит так...

function redraw() {
  trans = d3.event.translate;
  scale = d3.event.scale;
  vis.attr("transform", "translate(" + trans + ")" + " scale(" + scale + ")");
}

Однако этот метод масштабирует всю графику SVG, включая размеры шрифта, края графика, ширину обводки линий, окружающих узлы, и т. д.

Можно ли как-то не масштабировать определенные элементы? Единственное решение, которое я видел до сих пор, — это поместить такую ​​строку (взято отсюда http://jsfiddle.net/56RDx/2/)

node.attr("font-size", (nodeFontSize / d3.event.scale) + "px");

в методе перерисовки, чтобы в основном инвертировать масштабирование определенных элементов на лету. Однако моя проблема заключается в том (помимо того, что это уродливый хак), что ширина моих ребер динамически генерируется при рисовании графика (в соответствии с некоторыми свойствами графика...), поэтому этот метод "инверсии" не работает...


person fgysin    schedule 16.10.2012    source источник
comment
Почему бы не установить scale() на меньшее значение для отдельных фигур SVG?   -  person A.M.K    schedule 16.10.2012
comment
У вас есть демо и что вы пытаетесь не масштабировать?   -  person A.M.K    schedule 16.10.2012
comment
@AMK Код довольно большой, было бы трудно поместить его в демо... Но вот источник многих используемых функций: bl.ocks.org/2514276#index.html   -  person fgysin    schedule 16.10.2012
comment
@A.M.K. Как мне установить для «scale ()» меньшее значение только для некоторых форм SVG?   -  person fgysin    schedule 16.10.2012
comment
Неважно, это не сработает, пожалуйста, смотрите мой ответ ниже.   -  person A.M.K    schedule 16.10.2012


Ответы (2)


  1. вы можете добавить класс к элементу, для которого вы хотите активировать масштабирование:

    d3 ... .append('svg:g').classed("some_classname", true).call(d3.behavior.zoom().on("zoom", redraw))...
    

    затем выполните:

    function redraw() {
      trans = d3.event.translate;
      scale = d3.event.scale;
      vis.selectAll("some_classname").attr("transform", "translate(" + trans + ")" + " scale(" + scale + ")");
    }
    

  2. или вы можете добавить класс ко всем элементам, для которых вы не хотите запускать масштабирование, а затем использовать псевдокласс CSS3 :not:

    function redraw() {
      trans = d3.event.translate;
      scale = d3.event.scale;
      vis.selectAll("*:not(.some_classname)").attr("transform", "translate(" + trans + ")" + " scale(" + scale + ")");
    }
    
person hungastryke    schedule 07.11.2012

Единственное решение, которое я смог найти, - это "уродливый взлом", если (я предполагаю, что вы это делаете) вы пытаетесь, например, не масштабировать линии, вам следует попробовать следующее, это работает как для увеличения, так и для уменьшения масштаба:

Демонстрация: http://jsfiddle.net/SO_AMK/gJMTb/

JavaScript:

function redraw() {
  vis.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")");
  vis.attr("font-size", (nodeFontSize / d3.event.scale) + "px");
  vis.selectAll("line.link").style("stroke-width", getStrokeWidth); // Function so it runs for each element individually
}

function getStrokeWidth(){
    if (!this.__data__.stroke) { // Doesn't exist, so set it to the original stroke-width
        this.__data__.stroke = parseFloat(d3.select(this).style("stroke-width"));
        // I found __data__ to be easier than d3's .data()
    }
    return this.__data__.stroke / d3.event.scale + "px";
}

Подробнее об использовании функции с style() см. в документации.

person A.M.K    schedule 16.10.2012
comment
Однако я не уверен, что действительно понимаю, что здесь происходит... Внутри функции getStrokeWidth ссылка this указывает на элемент строки SVG, верно? Таким образом, свойство \_\_data\_\_ указывает на фактический элемент данных (край графа), добавленный с помощью D3. Но какое это имеет отношение к инсульту? Разве штрих не определен в элементе SVG, а не в элементе данных? - person fgysin; 17.10.2012
comment
Как только вы измените значение stroke-width, вы не сможете умножить его на d3.event.scale, потому что (d3.event.scale) это не относительное значение. Итак, я кэширую исходное значение stroke-width в объекте elements __data__, чтобы выполнить вычисления позже. Вы можете использовать console.log() для значений, чтобы лучше видеть, что происходит. - person A.M.K; 17.10.2012
comment
Забыл упомянуть, что __data__ — это то, что .data() D3 использует для хранения данных, поэтому вы также можете получить их через .data(). Но это создает несколько дополнительных объектов и не делает его проще. - person A.M.K; 17.10.2012