2016-04-12 2 views
0

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

Также, как бы я организовал легенду в сетке, чтобы использовать пустое пространство в верхней левой части диаграммы? Я создал скрипку с кодом, который я сейчас имею в https://jsfiddle.net/3f7xrgeb/, а также наклеил его ниже. Моя рабочая копия (если скрипка не отображается) находится на http://www.matthewedavis.net/Magdalene_playtext/test_bars.html.

Любая помощь будет оценена по достоинству.

var margin = {top: 50, right: 150, bottom: 50, left: 150}, 
     w = 2500 - margin.left - margin.right, 
     h = 500 - margin.top - margin.bottom; 

    d3.json("http://www.matthewedavis.net/Magdalene_playtext/test_chart.json", function(json) { 

     var data = json.items; 

     var test = function(d) { return d.starting_line + d.duration; }; 

     var stage_directions = ([44, 49, 114, 140, 209, 217, 249, 257, 265, 277, 305, 334, 358, 381, 398, 409, 440, 470, 491, 547, 555, 564, 572, 587, 614, 630, 640, 691, 704, 725, 743, 775, 793, 818, 823, 841, 845, 868, 872, 888, 902, 910, 920, 925, 963, 993, 1005, 1023, 1031, 1047, 1061, 1096, 1125, 1133, 1143, 1178, 1210, 1228, 1281, 1293, 1336, 1349, 1376, 1395, 1439, 1446, 1454, 1538, 1554, 1562, 1578, 1598, 1610, 1618, 1642, 1646, 1716, 1725, 1743, 1781, 1791, 1797, 1843, 1863, 1887, 1915, 1923, 1939 ,1972, 1989, 2019, 2031, 2039, 2045, 2073, 2085, 2101, 2123]) 

     var x = d3.scale.linear() 
     .domain([0, 2200]) 
     .range([0, w]); 

     var y = d3.scale.ordinal() 
     .domain(["The priest's cell","The Cloud","Wilderness","The mountain","The Lodge","Marseilles","The Ship","Heaven","Heathen Temple","Sepulchre","The Stations","Palace of the King of Marseilles","Lazarus' tomb","Simon the Leper's House","Arbor","Jherusalem","Tavern","Hellmouth","The Place","Stage Above Hell","King of Flesh's location","King of the World's location","Pilate's location","Herod's location","Magdalene Castle","Tiberius' Palace"]) 
     .rangeBands([0, h]); 

     var yAxis = d3.svg.axis() 
     .scale(y) 
     .orient("left"); 

     var xAxis = d3.svg.axis() 
     .scale(x) 
     .orient("bottom"); 

     var svg = d3.select("body").append("svg") 
     .attr("width", w + margin.left + margin.right) 
     .attr("height", h + margin.top + margin.bottom) 
     .append("g") 
     .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

     svg.append("text") 
     .attr("transform", "translate(" + (w/2) + " ," + (h + margin.bottom - 5) +")") 
     .style("text-anchor", "middle") 
     .text("Line Number"); 

     var t; 
     for (t in stage_directions){ 
     svg.append("rect") 
     .attr("class", "overlay") 
     .attr("x",stage_directions[t]) 
     .attr("width", 1) 
     .attr("height", h) 
     .style ("fill", "black") 
     .style ("opacity", 0.3); 
    } 

     svg.append("rect") 
     .attr("class", "overlay") 
     .attr("x",1) 
     .attr("width", 1133) 
     .attr("height", h) 
     .style ("fill", "red") 
     .style ("opacity", 0.1); 

     svg.append("rect") 
     .attr("class", "overlay") 
     .attr("x",1133) 
     .attr("width", 857) 
     .attr("height", h) 
     .style ("fill", "yellow") 
     .style ("opacity", 0.1); 

     svg.append("rect") 
     .attr("class", "overlay") 
     .attr("x",1990) 
     .attr("width", 134) 
     .attr("height", h) 
     .style ("fill", "green") 
     .style ("opacity", 0.1); 

     svg.append("g") 
     .attr("class", "x axis") 
     .attr("transform", "translate(0," + h + ")") 
     .call(xAxis); 

     svg.append("g") 
     .attr("class", "y axis") 
     .call(yAxis) 

     var bars = svg.selectAll(".bar") 
     .data(data) 
     .enter() 
     .append("rect") 
     .attr("class", function(d, i) {return "bar " + d.character;}) 
     .attr("x", function(d, i) {return d.starting_line;}) 
     .attr("y", function(d, i) {return y(d.location);}) 
     .attr("width", function(d, i) {return d.duration;}) 
     .attr("height", 15) 
     .style("fill", function(d,i) {return "#" + d.color;}); 


     var legend = svg.selectAll(".legend") 
     .data(data) 
     .enter().append("g") 
     .attr("class", "legend") 
     .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); 

     legend.append("rect") 
     .attr("x", 10) 
     .attr("width", 10) 
     .attr("height", 10) 
     .style("fill", function(d,i) {return "#" + d.color;}); 

     legend.append("text") 
     .attr("x", 22) 
     .attr("y", 5) 
     .attr("dy", ".35em") 
     .text(function(d) { return d.character; }); 

     svg.append("g") 
     .attr("class", "legend") 
     .call(legend) 
    }); 
+0

К сожалению, css не будет работать для этого, потому что мне нужно повторно использовать код с другими наборами данных и не могу каждый раз писать пользовательский CSS. Я нашел решение, хотя: В конце концов это будет использоваться для других наборов данных, поэтому создание пользовательского css для каждого набора может быть проблемой. Однако я нашел решение, которое я опубликую в качестве другого комментария. – medievalmatt

+0

'\t \t \t var listCharacters = d3.set (data.map (function (d) {return d.character})). Values ​​(); listColors = []; для (л в listCharacters) { для (ключа в данных вар) { , если (listCharacters [л] === Данные [ключ] .character) {если ( listColors.indexOf (данные [ключ] .color) > -1) {} еще { listColors.push (данные [ключ] .color) } } еще {}} } ' – medievalmatt

+0

Хорошо знать, что вы нашли решение для цветов. Кроме того, если мой ответ каким-то образом помог вам, это хорошая практика, чтобы признать это. –

ответ

0

Попробуйте это:

Во-первых, создать массив со списком символов, избегая дубликатов:

var listCharacters = d3.set(data.map(function(d){ return d.character})).values(); 

Затем, используйте его в качестве данных для вашей легенды:

var legend = svg.selectAll(".legend") 
.data(listCharacters) 
.enter() 
//the test of the code... 

И изменить text:

.text(function(d,i){ return listCharacters[i]}); 

Для цветов, сделать то же самое:

var listColors = d3.set(data.map(function(d){ return d.colour})).values(); //check the spelling in your object 

И цвет прямоугольники в соответствии с индексом:

.attr("fill", function(d,i){ return listColors[i]}); 

Чтобы понять, что он делает, пожалуйста, прочитайте это: https://github.com/mbostock/d3/wiki/Arrays

+0

Это приводит к последовательности черных ящиков без информации о тексте или цвете, и я не уверен, правильно ли она отображает последовательность или нет.Нужно ли мне также изменить разделы «rect» и «text» ниже, чтобы отразить это, или включить мою информацию о цвете в набор значений в операторе return для d3.set? – medievalmatt

+0

Я добавил к моему ответу, пожалуйста, посмотрите. –

+0

Это странно. Текстовые метки отлично работают, но цвета неправильно отображаются. Похоже, что d3.set не выставляет значения произвольно одинаковым образом каждый раз, когда он запускается. я должен посмотреть, есть ли способ обработать цвета по-разному - возможно, проверьте json на основе значений в списке символов. – medievalmatt

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