2013-04-01 3 views
2

Я создал диаграмму линии на примере здесь:d3 линии диаграмма этикетка перекрываться

http://bl.ocks.org/mbostock/3884955

Однако, с моими данными линейных меток (города) в конечном итоге перекрытие, так как конечные значения на ось y для разных линий часто близка. Я знаю, что мне нужно сравнить последнее значение для каждой строки и переместить ярлык вверх или вниз, когда значения отличаются на 12 единиц или меньше. Моя мысль взглянуть на текстовые метки, которые написаны на этом кусочке кода

city.append("text") 
.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; }) 
.attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.temperature) + ")"; }) 
.attr("x", 3) 
.attr("dy", ".35em") 
.text(function(d) { return d.name; }); 

Если у (d.value.temperature) значения отличаются на 12 или меньше, перемещать значения друг от друга, пока они не имеют по крайней мере, 12 единиц между ними. Любые мысли о том, как это сделать? Это мой первый проект d3, и синтаксис все еще дает мне возможность!

ответ

2

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

svg.selectAll("text.label").data(data) 
    .enter() 
    .append("text") 
    .attr("transform", function(d, i) { 
     var currenty = y(d.value.temperature); 
     if(i > 0) { 
      var previousy = y(data[i-1].value.temperature), 
      if(currenty - previousy < 12) { currenty = previousy + 12; } 
     } 
     return "translate(" + x(d.value.date) + "," + currenty + ")"; 
    }) 
    .attr("x", 3) 
    .attr("dy", ".35em") 
    .text(function(d) { return d.name; }); 

Это не учитывает тот факт, что предыдущая метка может быть перемещена. Вы можете получить позицию предыдущего ярлыка явно и переместить текущий в зависимости от этого. Код будет почти таким же, за исключением того, что вам нужно будет сохранить ссылку на текущий элемент() так, чтобы к нему можно было получить доступ позже.

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

+0

Если я что-то не хватает, это только проверяет этикетки для смежных линий для перекрытия. Если, например, метка для строки 1 и метка для строки 3 перекрываются, это не будет обнаружено и исправлено с помощью этой подпрограммы. Пожалуйста, дайте мне знать, если я неверно истолковал, что делает этот код. Благодаря! –

+0

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

+0

Точка хорошо сделана ... Спасибо, что успокоил меня, что я не пропущу что-то простое. –

1

Рассмотрите возможность использования макета D3 для размещения этикеток. Смотрите пример здесь: https://bl.ocks.org/wdickerson/bd654e61f536dcef3736f41e0ad87786

Предполагая, что у вас есть data массива, содержащие объекты с value собственности и масштаб y:

// Create some nodes 
const labels = data.map(d => { 
    return { 
    fx: 0, 
    targetY: y(d.value) 
    }; 
}); 

// Set up the force simulation 
const force = d3.forceSimulation() 
    .nodes(labels) 
    .force('collide', d3.forceCollide(10)) 
    .force('y', d3.forceY(d => d.targetY).strength(1))  
    .stop(); 

// Execute thte simulation 
for (let i = 0; i < 300; i++) force.tick(); 

// Assign values to the appropriate marker 
labels.sort((a, b) => a.y - b.y); 
data.sort((a, b) => b.value - a.value); 
data.forEach((d, i) => d.y = labels[i].y); 

Теперь ваш data массива будет иметь y свойства, представляющее его оптимальное положение.

Пример использует D3 4.0, читайте здесь: https://github.com/d3/d3-force