2012-08-08 37 views
51

Tôi bắt đầu với d3.js và đang cố gắng tạo một hàng các nút, mỗi nút chứa một nhãn số được căn giữa.Đặt nhãn ở giữa các nút trong d3.js

Tôi có thể tạo ra kết quả mong muốn một cách trực quan, nhưng cách tôi thực hiện nó hầu như không tối ưu vì nó liên quan đến việc mã hóa cứng toạ độ x-y cho từng phần tử văn bản. Dưới đây là các mã:

var svg_w = 800; 
var svg_h = 400; 
var svg = d3.select("body") 
    .append("svg") 
    .attr("width", svg_w) 
    .attr("weight", svg_h); 

var dataset = []; 
for (var i = 0; i < 6; i++) { 
    var datum = 10 + Math.round(Math.random() * 20); 
    dataset.push(datum); 
} 

var nodes = svg.append("g") 
       .attr("class", "nodes") 
       .selectAll("circle") 
       .data(dataset) 
       .enter() 
       .append("circle") 
       .attr("class", "node") 
       .attr("cx", function(d, i) { 
        return (i * 70) + 50; 
       }) 
       .attr("cy", svg_h/2) 
       .attr("r", 20); 

var labels = svg.append("g") 
       .attr("class", "labels") 
       .selectAll("text") 
       .data(dataset) 
       .enter() 
       .append("text") 
       .attr("dx", function(d, i) { 
        return (i * 70) + 42 
       }) 
       .attr("dy", svg_h/2 + 5) 
       .text(function(d) { 
        return d; 
       }); 

Các node lớp là lớp tùy chỉnh CSS Tôi đã xác định riêng cho circle yếu tố, trong khi lớp nodeslabels không được định nghĩa một cách rõ ràng và chúng được vay mượn từ answer này.

Như đã thấy, vị trí của mỗi nhãn văn bản được mã hóa cứng để nó xuất hiện ở giữa mỗi nút. Rõ ràng, đây không phải là giải pháp đúng.

Câu hỏi của tôi là làm thế nào tôi nên liên kết chính xác từng nhãn văn bản với mỗi vòng tròn nút động sao cho vị trí của nhãn thay đổi cùng với một vòng tròn tự động. Lời giải thích khái niệm là cực kỳ hoan nghênh với ví dụ mã.

+1

neo chữ dường như không làm việc trực tiếp trong D3, nhưng bạn đã cố gắng một cái gì đó đơn giản như CSS text-align? Cái này cần phải dùng mẹo! http://www.w3schools.com/cssref/pr_text_text-align.asp Ngoài ra, hãy thử xem các bài đăng như thế này từ Nhóm Google d3: https://groups.google.com/forum/#!searchin/d3 -js/text-align/d3-js/M6a-97ajkWs/rHJV4_WrhX0J% 5B1-25% 5D – paxRoman

+1

Bạn nhận được ý tưởng rằng neo văn bản không hoạt động ở đâu trong d3? –

+0

vài tháng trước, họ đã không làm việc ... nhờ làm rõ :) tốt đẹp để xem một cách tiếp cận đơn giản cho vấn đề này – paxRoman

Trả lời

61

Thuộc tính text-anchor hoạt động như mong đợi trên phần tử svg được tạo bởi D3. Tuy nhiên, bạn cần phải thêm textcircle vào một phần tử phổ biến g để đảm bảo rằng textcircle được căn giữa với nhau.

Để làm điều này, bạn có thể thay đổi biến nodes của bạn để:

var nodes = svg.append("g") 
      .attr("class", "nodes") 
      .selectAll("circle") 
      .data(dataset) 
      .enter() 
      // Add one g element for each data node here. 
      .append("g") 
      // Position the g element like the circle element used to be. 
      .attr("transform", function(d, i) { 
      // Set d.x and d.y here so that other elements can use it. d is 
      // expected to be an object here. 
      d.x = i * 70 + 50, 
      d.y = svg_h/2; 
      return "translate(" + d.x + "," + d.y + ")"; 
      }); 

Lưu ý rằng dataset bây giờ là một danh sách các đối tượng để d.yd.x thể được sử dụng thay vì chỉ là một danh sách các chuỗi.

Sau đó, thay thế circletext đang append của bạn như sau:

// Add a circle element to the previously added g element. 
nodes.append("circle") 
     .attr("class", "node") 
     .attr("r", 20); 

// Add a text element to the previously added g element. 
nodes.append("text") 
    .attr("text-anchor", "middle") 
    .text(function(d) { 
     return d.name; 
     }); 

Bây giờ, thay vì thay đổi vị trí của các circle bạn thay đổi vị trí của phần tử g trong đó di chuyển cả circletext .

Đây là một JSFiddle hiển thị văn bản trung tâm trên vòng kết nối.

Nếu bạn muốn có văn bản của bạn có trong một phần tử g riêng để nó luôn xuất hiện trên đầu trang, sau đó sử dụng d.xd.y giá trị thiết lập trong việc tạo ra các g yếu tố đầu tiên để transform văn bản.

var text = svg.append("svg:g").selectAll("g") 
     .data(force.nodes()) 
     .enter().append("svg:g"); 

text.append("svg:text") 
    .attr("text-anchor", "middle") 
    .text(function(d) { return d.name; }); 

text.attr("transform", function(d) { 
     return "translate(" + d.x + "," + d.y + ")"; 
    }); 
+0

cảm ơn cho câu trả lời! Dường như cách tiếp cận của bạn tương tự như cách tiếp cận đầu tiên được nêu trong [answer] (http://stackoverflow.com/questions/11102795/d3-node-labeling/11109803#11109803), có nghĩa là mỗi nhãn sẽ được vẽ * trên đầu trang chỉ cho vòng kết nối của nó *, nhưng sẽ được vẽ * bên dưới các vòng kết nối khác *. Có thể thực hiện nó bằng cách sử dụng cách tiếp cận hai dữ liệu tham gia được nêu trong cùng một câu trả lời không? (đó là những gì tôi đã mô hình hóa nỗ lực của mình). Cảm ơn! – skyork

+0

Tôi đã cập nhật cho việc này. Hai thứ chính bạn cần thay đổi là làm cho dữ liệu của bạn thành danh sách các đối tượng thay vì danh sách các chuỗi để 'y' và' x' có thể được lưu trữ cho mỗi chuỗi và đặt văn bản của bạn bên trong phần tử 'g' sao cho phần tử 'g' có thể được chuyển đổi. –

+0

nếu tôi hiểu mã cập nhật của bạn ở trên một cách chính xác, trước tiên bạn tạo một phần tử 'g' và bên trong đó bạn tạo một chuỗi các phần tử' g' cho dữ liệu trong mảng và sau đó bạn tạo các phần tử 'text' bên trong mỗi phần tử này. g' yếu tố? Điều gì làm tôi bối rối một chút là 'text.append (" svg: text ") ...', 'text' ở đây có đại diện cho chuỗi các phần tử' g' không? Nếu vậy, làm thế nào để D3 tạo một phần tử 'text' cho * mỗi phần tử' g' * này? Cú pháp là một chút sai lầm. – skyork

4

Trang này describes what's going on under the svg hood khi nói đến phần tử văn bản. Hiểu được cấu trúc dữ liệu và máy móc cơ bản đã giúp tôi có được sự xử lý tốt hơn về cách tôi phải sửa đổi mã của mình để làm cho nó hoạt động.

23

Câu trả lời tốt nhất came from the asker mình:

chỉ là một sự quan sát hơn nữa: chỉ với.attr ("text-anchor", "middle") cho mỗi phần tử văn bản, nhãn nằm ở giữa theo chiều ngang nhưng hơi tắt theo chiều dọc. Tôi đã sửa lỗi này bằng cách thêm attr ("y", ".3em") (mượn từ các ví dụ tại trang web d3.js), có vẻ như hoạt động tốt ngay cả đối với kích thước tùy ý của vòng tròn nút. Tuy nhiên, những gì chính xác này thuộc tính bổ sung không eludes sự hiểu biết của tôi. Chắc chắn, nó có điều gì đó về tọa độ y của từng phần tử văn bản, nhưng tại sao .3em trong số cụ thể? Dường như nó gần như kỳ diệu đối với tôi ...

Chỉ cần thêm .attr("text-anchor", "middle") vào từng yếu tố văn bản.

Ví dụ:

node.append("text") 
    .attr("x", 0) 
    .attr("dy", ".35em") 
    .attr("text-anchor", "middle") 
    .text(function(d) { return d.name; }); 
+0

Bỏ qua câu trả lời đã chọn. Đây là một cách tiếp cận tốt hơn. – Matt

+0

Chà. Điều tốt tôi đã cuộn xuống câu trả lời tiếp theo. Sự lười biếng của tôi vì không đọc câu trả lời đã chọn đã được đền đáp. – Martin

+0

Trong khi sử dụng, HTML của tôi có văn bản nhưng nó không hiển thị trong nút thực của tôi. –