2012-11-02 37 views
49

Tôi đang trong quá trình học cuối cùng D3 và tôi tình cờ gặp một vấn đề mà tôi không thể tìm thấy câu trả lời. Tôi không chắc chắn nếu câu hỏi của tôi là bởi vì tôi không nghĩ về thành ngữ với thư viện, hoặc nếu đó là vì một thủ tục mà tôi hiện không biết. Tôi cũng nên đề cập đến rằng tôi đã chỉ bắt đầu làm những thứ liên quan đến web vào tháng Sáu, vì vậy tôi khá mới với javascript.D3, phụ đề lồng nhau và luồng dữ liệu

Giả sử chúng tôi đang tạo công cụ cung cấp cho người dùng một danh sách các loại thực phẩm có hình ảnh tương ứng. Và cho phép thêm vào ràng buộc bổ sung mà mỗi mục danh sách cần được gắn nhãn bằng một ID duy nhất để nó có thể được liên kết với một chế độ xem khác. Trực giác đầu tiên của tôi để giải quyết vấn đề này là tạo ra một danh sách gồm <div> mỗi ID có ID riêng của họ, trong đó mỗi div<p><img> riêng. HTML kết quả sẽ giống như thế:

<div id="chocolate"> 
    <p>Chocolate Cookie</p> 
    <img src="chocolate.jpg" /> 
</div> 
<div id="sugar"> 
    <p>Sugar Cookie</p> 
    <img src="sugar.jpg" /> 
</div> 

Các dữ liệu cho công cụ này là trong một mảng JSON, nơi một JSON cá nhân trông giống như:

{ "label": "sugar", "text": "Sugar Cookie", "img": "sugar.jpg" } 

Có cách nào để làm tạo ra HTML trong một ngã swoop? Bắt đầu với một trường hợp cơ sở của việc thêm một div, mã có thể giống như thế:

d3.select(containerId).selectAll('div')               
    .data(food) 
    .enter().append('div') 
    .attr('id', function(d) { return d.label; }); 

Bây giờ, những gì về việc thêm một <div> với một <p> trong nó? suy nghĩ ban đầu của tôi là phải làm một cái gì đó như:

d3.select(containerId).selectAll('div')               
    .data(food) 
    .enter().append('div') 
    .attr('id', function(d) { return d.label; }) 
     .append('p').text('somethingHere'); 

Nhưng, tôi thấy hai vấn đề với điều này: (1) làm thế nào để bạn nhận được dữ liệu từ các yếu tố div, và (2) làm thế nào bạn có thể thêm nhiều trẻ em cùng một phụ huynh trong một chuỗi khai báo? Tôi không thể nghĩ ra cách để thực hiện bước thứ ba, nơi tôi sẽ nối thêm vào img.

Tôi đã đề cập đến lựa chọn lồng nhau trên một bài đăng khác, trỏ đến http://bost.ocks.org/mike/nest/. Nhưng là lựa chọn lồng nhau, và do đó phá vỡ các phụ thêm vào ba khối, thích hợp/thành ngữ cho tình huống này? Hay thực sự là một cách được xây dựng tốt để tạo thành cấu trúc này trong một chuỗi khai báo? Nó có vẻ như có thể có một cách với các cuộc bầu cử được đề cập trên https://github.com/mbostock/d3/wiki/Selections, nhưng tôi không đủ quen thuộc với ngôn ngữ để kiểm tra giả thuyết đó.

Từ cấp độ khái niệm, ba đối tượng này (div, pimg) được coi như một nhóm chứ không phải các thực thể riêng biệt, và sẽ tốt hơn nếu mã phản ánh điều đó.

Trả lời

69

Bạn không thể thêm nhiều phần tử con trong một chuỗi lệnh. Bạn sẽ cần phải lưu lựa chọn cha mẹ trong một biến. Điều này sẽ làm những gì bạn muốn:

var data = [{ "label": "chocolate", "text": "Chocolate Cookie", "img": "chocolate.jpg" }, 
     { "label": "sugar", "text": "Sugar Cookie", "img": "sugar.jpg" }]; 

var diventer = d3.select("body").selectAll("div") 
    .data(data) 
    .enter().append("div") 
    .attr("id", function(d) { return d.label; }); 

diventer.append("p") 
    .text(function(d) { return d.text; }); 

diventer.append("img") 
    .attr("src", function(d) { return d.img; });​ 

Xem fiddle làm việc: http://jsfiddle.net/UNjuP/

Bạn đang tự hỏi làm thế nào một phần tử con như p hoặc img, được truy cập vào dữ liệu được liên kết với mẹ của nó. Dữ liệu được kế thừa tự động từ cha mẹ khi bạn thêm một phần tử mới. Điều này có nghĩa là các phần tử p và img sẽ có cùng một dữ liệu được liên kết với chúng như div cha.

Việc sao chép dữ liệu này không phải là duy nhất cho phương thức append.Điều này xảy ra với các phương pháp selection sau: append, insertselect.

Ví dụ, đối selection.append:

selection.append (tên)

Gắn một yếu tố mới với tên được chỉ định như đứa trẻ cuối cùng của mỗi yếu tố trong việc lựa chọn hiện tại. Trả về lựa chọn mới chứa các phần tử được nối thêm. Mỗi phần tử mới kế thừa dữ liệu của các phần tử hiện tại, nếu có, theo cách tương tự như chọn cho các tùy chọn con số . Tên phải được chỉ định dưới dạng hằng số, mặc dù trong tương lai , chúng tôi có thể cho phép thêm phần tử hiện tại hoặc hàm vào tạo tên động.

Vui lòng hỏi chi tiết nếu có điều gì đó không rõ ràng.


EDIT

Bạn có thể thêm nhiều phần tử con mà không cần lưu trữ các lựa chọn trong một biến bằng cách sử dụng phương pháp selection.each. Bạn có thể sau đó cũng trực tiếp truy cập dữ liệu từ phụ huynh:

var data = [{ "label": "chocolate", "text": "Chocolate Cookie", "img": "chocolate.jpg" }, 
     { "label": "sugar", "text": "Sugar Cookie", "img": "sugar.jpg" }]; 

d3.select("body").selectAll("div") 
    .data(data) 
    .enter().append("div") 
    .attr("id", function(d) { return d.label; }) 
    .each(function(d) { 
     d3.select(this).append("p") 
      .text(d.text); 
     d3.select(this).append("img") 
      .attr("src", d.img); 
    }); 
+6

Tuyệt vời! Tôi đã không nhận ra rằng các nút con có cùng phạm vi dữ liệu. Cảm ơn bạn đã làm rõ :) –

+3

Được bỏ phiếu để sử dụng 'selection.each'. – Yawar

+2

Nếu bạn sử dụng 'selection.each' để chèn các nút được nhóm (hoặc lồng nhau), hãy nhớ sử dụng' selection.each' cho bước cập nhật (và cũng có thể cho bước thoát). – npdoty

3

Đây không phải là hoàn toàn khác nhau từ nautat's answer, nhưng tôi nghĩ rằng mã có thể được thực hiện một chút bụi bằng cách tiết kiệm lựa chọn cập nhật chứ không phải là nhập lựa chọn và nhận được nhập lựa chọn từ nó cho một hoạt động cần nó (thêm div xung quanh).

Khi bạn chèn hoặc nối thêm phần tử vào lựa chọn nhập(), nó được thêm vào lựa chọn cập nhật mà bạn có thể làm việc sau đó. Điều này có nghĩa là bạn có thể tham gia dữ liệu, sau đó thêm div với lựa chọn nhập và sau đó khi bạn nối với lựa chọn cập nhật, bạn sẽ thêm trong số số div bạn đã thêm vào lựa chọn nhập:

var cookies = [ 
 
    { "label": "sugar", "text": "Sugar Cookie", "img": "sugar.jpg" }, 
 
    { "label": "chocolate", "text": "Chocolate Cookie", "img": "chocolate.jpg" }]; 
 

 
var cookie = d3.select("#cookie-jar").selectAll().data(cookies); 
 
cookie.enter().append("div"); 
 
cookie.append("p").text(function(d){ return d.text }); 
 
cookie.append("img").attr("src",function(d){ return d.img });
#cookie-jar div { border: solid 1px black; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 
 
<div id="cookie-jar"></div>

19

Một lần nữa, không substantively khác nhau, nhưng phương pháp ưa thích của tôi sẽ được sử dụng 'gọi'

var data = [{ "label": "chocolate", "text": "Chocolate Cookie", "img": "chocolate.jpg" }, 
     { "label": "sugar", "text": "Sugar Cookie", "img": "sugar.jpg" }]; 

d3.select("body").selectAll("div") 
    .data(data) 
    .enter().append("div") 
    .attr("id", function(d) { return d.label; }) 
    .call(function(parent){ 
    parent.append('p').text(function(d){ return d.text; }); 
    parent.append('img').attr("src", function(d) { return d.img; });​ 
    }); 

bạn không cần phải lưu trữ bất kỳ vari ables và bạn có thể tính ra hàm được gọi nếu bạn muốn sử dụng một cấu trúc tương tự ở nơi khác.

+0

thích nó!điều này làm cho nó siêu dễ dàng cho tôi để xử lý cập nhật các đối tượng lồng nhau sâu – ptim

+0

điều này phù hợp với nhu cầu của tôi tốt hơn nhiều so với ở trên, vì tôi không có dữ liệu và tôi chỉ muốn sử dụng lại một phụ huynh bên trong mà không cần sử dụng biến bên ngoài bạn! –

Các vấn đề liên quan