2015-06-02 3 views
7

Я пытаюсь объединить два примера Майка: Zoomable Circle Packing + Automatic Text Sizing.Масштабируемая упаковка кругов с автоматическим оформлением текста в D3.js

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

Я не уверен, что мне нужно изменить преобразование или изменить часть, которая вычисляет размер шрифта.

Вот мой codepen: http://codepen.io/anon/pen/GJWqrL

var circleFill = function(d) { 
    if (d['color']) { 
     return d.color; 
    } else { 
     return d.children ? color(d.depth) : '#FFF'; 
    } 
} 

var calculateTextFontSize = function(d) { 
    return Math.min(2 * d.r, (2 * d.r - 8)/this.getComputedTextLength() * 11) + "px"; 
} 

var margin = 20, 
    diameter = 960; 

var color = d3.scale.linear() 
    .domain([-1, 18]) 
    .range(["hsl(0,0%,100%)", "hsl(228,30%,40%)"]) 
    .interpolate(d3.interpolateHcl); 

var pack = d3.layout.pack() 
    .padding(2) 
    .size([diameter - margin, diameter - margin]) 
    .value(function(d) { 
     return d.size; 
    }) 

var svg = d3.select("body").append("svg") 
    .attr("width", window.innerWidth) 
    .attr("height", window.innerHeight) 
    .append("g") 
    .attr("transform", "translate(" + diameter/2 + "," + diameter/2 + ")"); 

var focus = root, 
    nodes = pack.nodes(root), 
    view; 

var circle = svg.selectAll("circle") 
    .data(nodes) 
    .enter().append("circle") 
    .attr("class", function(d) { 
     return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"; 
    }) 
    .style("fill", circleFill) 
    .on("click", function(d) { 
     if (focus !== d) zoom(d), d3.event.stopPropagation(); 
    }); 

circle.append("svg:title") 
    .text(function(d) { 
     return d.name; 
    }) 

var text = svg.selectAll("text") 
    .data(nodes) 
    .enter().append("text") 
    .attr("class", "label") 
    .style("fill-opacity", function(d) { 
     return d.parent === root ? 1 : 0; 
    }) 
    .style("display", function(d) { 
     return d.parent === root ? null : "none"; 
    }) 
    .text(function(d) { 
     return d.name; 
    }) 
    .style("font-size", calculateTextFontSize) 
    .attr("dy", ".35em"); 

var node = svg.selectAll("circle,text"); 

d3.select("body") 
    .style("background", color(-1)) 
    .on("click", function() { 
     zoom(root); 
    }); 

zoomTo([root.x, root.y, root.r * 2 + margin]); 

function zoom(d) { 
    var focus0 = focus; 
    focus = d; 

    var transition = d3.transition() 
     .duration(d3.event.altKey ? 7500 : 750) 
     .tween("zoom", function(d) { 
      var i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2 + margin]); 
      return function(t) { 
       zoomTo(i(t)); 
      }; 
     }); 

    transition.selectAll("text") 
     .filter(function(d) { 
      return d.parent === focus || this.style.display === "inline"; 
     }) 
     .style("fill-opacity", function(d) { 
      return d.parent === focus ? 1 : 0; 
     }) 
     .each("start", function(d) { 
      if (d.parent === focus) this.style.display = "inline"; 
     }) 
     .each("end", function(d) { 
      if (d.parent !== focus) this.style.display = "none"; 
     }); 
} 

function zoomTo(v) { 
    var k = diameter/v[2]; 
    view = v; 
    node.attr("transform", function(d) { 
     return "translate(" + (d.x - v[0]) * k + "," + (d.y - v[1]) * k + ")"; 
    }); 
    circle.attr("r", function(d) { 
     return d.r * k; 
    }); 
} 

d3.select(self.frameElement).style("height", diameter + "px"); 

Щелчок по величине суб-круг в "ВИС" круг иллюстрирует проблему.

https://dl.dropboxusercontent.com/u/3040414/vis-circle.png

+1

Он смотрит на меня, как он работает нормально для всех разделов, кроме vis на верхнем уровне. Даже дети визы в порядке. Есть ли что-то другое в отношении? – couchand

+0

Некоторые из суб-кружков выглядят отлично, но нажмите на некоторые из кругов в круге «Вис», чтобы увидеть проблему. https://dl.dropboxusercontent.com/u/3040414/vis-circle.png –

+0

Даже в ваших данных нет круга «Вис» ... если я ищу ваш JS, нет «Vis». О чем ты говоришь? –

ответ

3

Сначала дайте идентификатор к кругу, здесь я даю имя текста как круг ID, так что я могу связать текст и его круг через текстовое имя.

var circle = svg.selectAll("circle") 
    .data(nodes) 
    .enter().append("circle") 
    .attr("class", function(d) { 
    return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"; 
    }) 
    .style("fill", circleFill) 
    .attr("r", function(d) { 
    return d.r; 
    }) 
    .attr("id", function(d) { 
    return d.name;//setting text name as the ID 
    }) 
    .on("click", function(d) { 
    if (focus !== d) zoom(d), d3.event.stopPropagation(); 
    }); 

О переходе полной из zoom(d) function (т.е. при нажатии на окружности и масштабирование) добавить функцию тайм-аут, который будет пересчитывать размер шрифта текста на основе увеличения.

setTimeout(function() { 
    d3.selectAll("text").filter(function(d) { 
    return d.parent === focus || this.style.display === "inline"; 
    }).style("font-size", calculateTextFontSize);//calculate the font 
}, 500) 

Ваша calculateTextFontSize функция будет выглядеть следующим образом (я использую радиус реального DOM для вычисления размера шрифта):

var calculateTextFontSize = function(d) { 
    var id = d3.select(this).text(); 
    var radius = 0; 
    if (d.fontsize){ 
    //if fontsize is already calculated use that. 
    return d.fontsize; 
    } 
    if (!d.computed) { 
    //if computed not present get & store the getComputedTextLength() of the text field 
    d.computed = this.getComputedTextLength(); 
    if(d.computed != 0){ 
     //if computed is not 0 then get the visual radius of DOM 
     var r = d3.selectAll("#" + id).attr("r"); 
     //if radius present in DOM use that 
     if (r) { 
     radius = r; 
     } 
     //calculate the font size and store it in object for future 
     d.fontsize = (2 * radius - 8)/d.computed * 24 + "px"; 
     return d.fontsize; 
    } 
    } 
} 

Рабочий код here

+0

Спасибо за ответ. Интересное использование тайм-аута. Я правильно ответил на этот ответ, так как он работает с данными образца вспышки, которые я предоставил. К сожалению, он не работает на 100% для моих фактических данных, которые больше. Я подозреваю, что это связано с сроками. –

+0

, если у вас нет каких-либо проблем при совместном использовании вашего набора данных, вы можете сделать его доступным для gist, я посмотрю. интегрируя его с текущим примером. – Cyril

+0

@ Кирилл Большое вам спасибо, это было большой помощью. Есть еще одна вещь, которую я хочу сделать, я хотел показать фотографии в листовых узлах, я передаю это из корневых данных, но как я могу отобразить это в круг? – void

1

У меня также была такая же проблема, как вы и я попытался это одно, и это работает для меня.

D3.js Auto font-sizing based on nodes individual radius/diameter

+0

Я пытаюсь применить это, однако ограничительная рамка для моих узлов верхнего уровня равна 0 , 0, что делает масштаб = бесконечность. У вас есть рабочий код где-то в сети (github, jsfiddle, codepen)? –

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