Как сделать метки d3 в центре javascript [duplicate]

Кодирование с тазобедренного сустава было бы примерно таким:

java.lang.reflect.Method method;
try {
  method = obj.getClass().getMethod(methodName, param1.class, param2.class, ..);
} catch (SecurityException e) { ... }
  catch (NoSuchMethodException e) { ... }

Параметры идентифицируют очень специфический вам метод (если есть несколько перегруженных доступных, если метод не имеет аргументов, methodName).

Затем вы вызываете этот метод, вызывая

try {
  method.invoke(obj, arg1, arg2,...);
} catch (IllegalArgumentException e) { ... }
  catch (IllegalAccessException e) { ... }
  catch (InvocationTargetException e) { ... }

. Опять же, оставьте аргументы в .invoke, если у вас их нет. Но да. Читайте о Java Reflection

2
задан Gerardo Furtado 16 January 2018 в 11:54
поделиться

1 ответ

Проблема с вашим вопросом не имеет ничего общего с программированием, JavaScript или D3 ... проблема является базовой концепцией dataviz (поэтому я добавил тэг в ваш вопрос ):

То, что вы пытаетесь сделать, неверно! Вы не должны использовать бары с временной шкалой. Временные шкалы предназначены для временных рядов (в которых мы используем точки или точки, соединенные линиями).

Если вы используете бары со временем по оси x, вы столкнетесь с проблемами:

  1. Позиционирование панели: левое поле панели всегда будет на дату, когда вы задавать. Вся строка будет лежать после этой даты;
  2. Установка ширины полосы: в реальной гистограмме, которая использует категориальные переменные для оси x, ширина не имеет значения. Но в масштабе времени ширина представляет время.

Однако, просто для объяснения, давайте создадим эту гистограмму с временным масштабом (несмотря на то, что это неправильный выбор) ... Вот как это сделать:

Во-первых, установите «ширину» полос во времени. Предположим, что каждый бар будет иметь 10-дневную ширину:

.attr("width", function(d){
    return x(d3.timeDay.offset(d.date, 10)) - x(d.date)
})

Затем установите положение x на панели до текущей даты, менее половины ее ширины (то есть менее 5 дней в нашем пример):

.attr('x', function(d, i) {
    return x(d3.timeDay.offset(d.date, -5));
})

Наконец, не забудьте создать «отступы» в шкале времени:

var x = d3.scaleTime()
  .domain([d3.min(data, function(d) {
    return d3.timeDay.offset(d.date, -10);
  }), d3.max(data, function(d) {
    return d3.timeDay.offset(d.date, 10);
  })])
  .range([0, width]);

Вот ваш код с этими изменениями:

var keys = [];
var legendKeys = [];

var maxVal = [];

var w = 800;
var h = 450;

var margin = {
  top: 30,
  bottom: 40,
  left: 50,
  right: 20,
};

var width = w - margin.left - margin.right;
var height = h - margin.top - margin.bottom;

var colors = ['#FF9A00', '#FFEBB6', '#FFC400', '#B4EDA0', '#FF4436'];

var data = [{
    "one": 4306,
    "two": 2465,
    "three": 2299,
    "four": 988,
    "five": 554,
    "six": 1841,
    "date": "2015-05-31T00:00:00"
  }, {
    "one": 4378,
    "two": 2457,
    "three": 2348,
    "four": 1021,
    "five": 498,
    "six": 1921,
    "date": "2015-06-30T00:00:00"
  }, {
    "one": 3404,
    "two": 2348,
    "three": 1655,
    "four": 809,
    "five": 473,
    "six": 1056,
    "date": "2015-07-31T00:00:00"
  },

];

data.forEach(function(d) {
  d.date = new Date(d.date)
})

for (var i = 0; i < data.length; i++) {
  for (var key in data[i]) {
    if (!data.hasOwnProperty(key) && key !== "date")
      maxVal.push(data[i][key]);
  }
}

var x = d3.scaleTime()
  .domain([d3.min(data, function(d) {
    return d3.timeDay.offset(d.date, -10);
  }), d3.max(data, function(d) {
    return d3.timeDay.offset(d.date, 10);
  })])
  .range([0, width]);

var y = d3.scaleLinear()
  .domain([0, d3.max(maxVal, function(d) {
    return d;
  })])
  .range([height, 0]);

var svg = d3.select('body').append('svg')
  .attr('class', 'chart')
  .attr('width', w)
  .attr('height', h);

var chart = svg.append('g')
  .classed('graph', true)
  .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

var layersArea = chart.append('g')
  .attr('class', 'layers');


var layers = layersArea.append('g')
  .attr('class', 'layer');

layers.selectAll('rect')
  .data(data)
  .enter()
  .append('rect')

.attr('height', function(d, i) {
  return height - y(d.one);
})

.attr('y', function(d, i) {
  return y(d.one);
})

// .attr('width', function(d, i) {
//   return 50;
// })

.attr("width", function(d) {
  return x(d3.timeDay.offset(d.date, 10)) - x(d.date)
})

.attr('x', function(d, i) {
  return x(d3.timeDay.offset(d.date, -5));
})

.style('fill', (d, i) => {
  return colors[i];
});

chart.append('g')
  .classed('x axis', true)
  .attr("transform", "translate(0," + height + ")")
  .call(d3.axisBottom(x)
    .tickFormat(d3.timeFormat("%Y-%m-%d")).tickValues(data.map(function(d) {
      return new Date(d.date)
    })));

chart.append('g')
  .classed('y axis', true)
  .call(d3.axisLeft(y)
    .ticks(10));
<script src="https://d3js.org/d3.v4.min.js"></script>

3
ответ дан Gerardo Furtado 16 August 2018 в 11:29
поделиться
  • 1
    Херардо, спасибо за вашу помощь. Я понимаю, что вы сейчас имеете в виду, не используя scaleTime. Меня не интересует время или данные между этими датами. Он просто покажет данные за этот месяц. Будет ли я лучше использовать scaleLinear для дат на оси x, поскольку они всего лишь момент времени, они могут быть месяцами. Мне просто нужно преобразовать отметку времени в данных на читаемую дату – ttmt 16 January 2018 в 12:18
  • 2
    В этом случае вы можете использовать шкалу диапазона, просто передавая строки. – Gerardo Furtado 17 January 2018 в 12:44
Другие вопросы по тегам:

Похожие вопросы: