В масштабируемых солнечных лучах D3, как мне сделать маркировку зависимой от уровня масштабирования?

Я пытаюсь визуализировать большую базу данных с масштабируемой диаграммой солнечных лучей. У меня слишком много дочерних элементов на нижних иерархических уровнях моего json, поэтому текстовые метки очень загромождены и нечитаемы на внешних краях.

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

Мой вопрос: как вычислить «относительную» глубину при определенном уровне масштабирования, а затем отображать метки на основе этого?

Насколько я понимаю, d.depth обозначает только абсолютные уровни.


person user2991908    schedule 25.01.2014    source источник
comment
Что вы имеете в виду под относительной глубиной?   -  person Lars Kotthoff    schedule 26.01.2014
comment
Допустим, есть 5 уровней. В основном виде отображаются все 5 уровней. В этом представлении я хочу, чтобы только уровни 1,2,3 отображали полный текст, а уровни 4,5 отображали сокращенный текст или не отображали его. Затем, при увеличении на один уровень, у нас отображаются уровни 2,3,4,5. На этот раз я хочу, чтобы уровни 2,3,4 были полностью помечены, а уровень 5 сокращен. Итак, при любом увеличении я хочу, чтобы 3 нижних отображаемых уровня имели полный текст, а остальные - сокращенные.   -  person user2991908    schedule 26.01.2014
comment
Возможно, вам лучше выяснить, достаточно ли места для метки - см. if-there-is-enough-space" title="d3 поместите метки дуг на круговую диаграмму, если места достаточно"> stackoverflow.com/questions/19792552/   -  person Lars Kotthoff    schedule 26.01.2014


Ответы (2)


Я предполагаю, что вы работаете с примером Джейсона Дэвиса.

Соответствующий код из его сценария

  function click(d) {
    path.transition()
      .duration(duration)
      .attrTween("d", arcTween(d));

    // Somewhat of a hack as we rely on arcTween updating the scales.
    text.style("visibility", function(e) {
          return isParentOf(d, e) ? null : d3.select(this).style("visibility");
        })
      .transition()
        .duration(duration)
        .attrTween("text-anchor", function(d) {
          return function() {
            return x(d.x + d.dx / 2) > Math.PI ? "end" : "start";
          };
        })
        .attrTween("transform", function(d) {
          var multiline = (d.name || "").split(" ").length > 1;
          return function() {
            var angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90,
                rotate = angle + (multiline ? -.5 : 0);
            return "rotate(" + rotate + ")translate(" 
                    + (y(d.y) + padding) + ")rotate(" 
                    + (angle > 90 ? -180 : 0) + ")";
          };
        })
        .style("fill-opacity", function(e) { 
                 return isParentOf(d, e) ? 1 : 1e-6; 
        })
        .each("end", function(e) {
          d3.select(this).style("visibility", 
                    isParentOf(d, e) ? null : "hidden");
        });
  }

Обратите внимание, как некоторые из этих функций ссылаются на два разных объекта данных, d и e. Это потому, что, если он не маскируется внутренней функцией, d внутри функции щелчка является объектом данных элемента, по которому щелкнули, — того, который становится центром круга.

Если он дает внутренней функции другое имя для объекта данных (function(e){}), то это объект данных, связанный с отдельным элементом, атрибуты которого изменены. Таким образом, он может вызывать функции, которые сравнивают два объекта данных, чтобы определить, должен ли данный элемент быть скрыт или нет на этом уровне масштабирования.

Вы хотите сделать то же самое, за исключением того, что вы не только скрываете текст, если он является родителем центрального колеса, вы также скрываете его, если он является слишком глубоким потомком. Итак, вы хотите что-то вроде:

          if (e.depth > d.depth + 3) return "hidden";

То, куда вы добавите этот код, зависит от выбора стиля — Джейсон Дэвис на самом деле меняет непрозрачность или видимость текста в трех точках: видимость устанавливается до и после перехода (во время события «конец»), а между ними непрозрачность исчезает. Вы хотите, чтобы ваши метки появлялись и исчезали одним щелчком мыши, или вы хотите, чтобы они исчезали и появлялись?

person AmeliaBR    schedule 26.01.2014
comment
Рад это слышать. Отметьте его как принятый, чтобы он больше не отображался в списке вопросов без ответов. - person AmeliaBR; 30.01.2014
comment
У меня есть дополнительный вопрос: если, исходя из тех же условий, я хочу изменить сам текст, а не только его видимость, могу ли я это сделать? Например, если я хочу сначала отобразить только одно слово на внешней спице, но как только мы увеличим масштаб, я хочу отобразить больше. - person user2991908; 04.02.2014
comment
Да, вы должны иметь возможность использовать аналогичное сравнение между двумя уровнями глубины в любой из функций. Для изменения текста (который не поддерживает переход) вы, вероятно, захотите также сделать это в конечной функции, просто добавьте вызов .text((/*test condition*/? /*value*/:/*other value*/ ) после функции стиля видимости. - person AmeliaBR; 05.02.2014

Я пока не могу комментировать, поэтому вот кое-что, что может оказаться полезным, если вы будете искать код Дэвиса на его стороне и найдете уменьшенную версию, которая вообще не поможет с этим ответом — полная версия перемещена сюда: https://code.google.com/p/testprogramming/source/browse/trunk/javascript/svg/d3/test/wheel.js?r=394&spec=svn394

Вся важная функция isParentOf отсутствует в приведенном выше ответе и должна быть получена из полной версии.

-- дополнительная информация: если вы хотите, чтобы метка отображалась на основе уровня «масштабирования», также важно отметить, что солнечные лучи не используют функцию .zoom(), и вам придется найти путь вручную. В моем случае я хотел скрыть все метки на верхнем уровне масштабирования, но показать их, если был выбран любой другой уровень. Для этого я сначала скрываю текст, а затем при каждом нажатии использую следующий тест

    var text = g.append("text")
    .attr("class","mylabel")
    .attr("transform", function(d) { return "rotate(" + computeTextRotation(d) + ")"; })
    .attr("x", function(d) { return y(d.y); })
    .attr("dx", "4") // left - margin for text
    .attr("dy", ".25em") // vertical-align of text in cell
    .text(function(d) { return (d.name == 'root') ? ('') : d.name; })
    .attr("font-size", function(d) { return d.ci_type === 'type' ? 12 : 10}) //font-size of text
    //.attr("visibility",function(d) { return d.dx < 0.009? "hidden" : "visible"}) // hide text of labels of partitions less than 2%
    .attr("visibility", "hidden") // hide labels at root level - starting level


    function click(d) {
    // fade out all text elements
    text.transition().attr("opacity", 0);
    path.transition()
    .duration(750)
    .attrTween("d", arcTween(d))
    .each("end", function(e, i) {
      // check if the animated element's data e lies within the visible angle span given in d
      if (e.x >= d.x && e.x < (d.x + d.dx)) {
        // get a selection of the associated text element
        var arcText = d3.select(this.parentNode).select("text");
        // fade in the text element and recalculate positions
        arcText.transition().duration(750)
          .attr("opacity", 1)
          .attr("transform", function() { return "rotate(" + computeTextRotation(e) + ")" })
          .attr("x", function(d) { return y(d.y); })

      }
    });


    // if the vis is at the 'root' level hide text, otherwise show    <! here is the test!  
    var str = d.name;
    var patt = 'root';
    var atRoot = (str === patt) ? true : false ;

    //console.log(atRoot); 

    //console.log( d.name ) ;

    text.attr("visibility",function(d) { return atRoot ? "hidden" : "visible"})  


    // end of click      
     }
person ASheppardWork    schedule 23.09.2015