Как мне назначить тики равными значению ключа, отличающемуся от того же объекта, из которого основан ось в D3. js? - PullRequest
0 голосов
/ 05 апреля 2020

Так что в основном у меня есть массив объектов, подобных этому:

{
  "year": 1753,
  "month": 1,
  "monthStr": "January",
  "variance": -1.366
}

В настоящее время мой yAxis основан на значении цифры c месяца ("месяц": 1), но я бы подобно фактическим тикам yAxis, чтобы быть строковыми значениями соответствующих объектов, которые хранятся под ключом "monthStr", чем теми числами, которые хранятся под ключом "месяц".

Пример. вместо того, чтобы иметь [1, 2, 3, 4 и т. Д. c.] По оси Y, которую я хотел бы, чтобы ["январь", "февраль", "март", "апрель" и т. Д. c.] Отображались в логическом порядке.

const yScale = d3.scaleTime()
.domain([d3.min(dataset, yValue), d3.max(dataset, yValue)])
.range([0, innerHeight]);

const yAxis = d3.axisLeft(yScale).tickFormat(d => d3.timeFormat('%M')( new Date(0).setMonth(d) ));

Я пытался передать различные параметры в .tickFormat(), но не могу заставить его работать так, как хотелось бы с этими соответствующими строками. Не могли бы вы помочь мне найти решение здесь?

function addMonthStrings (dataset) {
  for (let i=0; i < dataset.length; i++) {
    let newPropName = 'monthStr';
    switch (dataset[i]['month']) {
      case 1:
        dataset[i][newPropName] = 'January';
        break;
      case 2:
        dataset[i][newPropName] = 'February';
        break;
      case 3:
        dataset[i][newPropName] = 'March';
        break;
      case 4:
        dataset[i][newPropName] = 'April';
        break;
      case 5:
        dataset[i][newPropName] = 'May';
        break;
      case 6:
        dataset[i][newPropName] = 'June';
        break;
      case 7:
        dataset[i][newPropName] = 'July';
        break;
      case 8:
        dataset[i][newPropName] = 'August';
        break;
      case 9:
        dataset[i][newPropName] = 'September';
        break;
      case 10:
        dataset[i][newPropName] = 'October';
        break;
      case 11:
        dataset[i][newPropName] = 'November';
        break;
      case 12:
        dataset[i][newPropName] = 'December';
        break;
    };
  };
};

const render = (baseTemperature, dataset) => {
  const width = 960;
  const height = 500;
  
  const xValue = d => d['year'];
  const yValue = d => d['month'];
  const monthStr = d => d['monthStr'];
  const variance = d => Math.round10(d['variance'], -1);
  const currTemp = d => Math.round10(baseTemperature - d['variance'], -1);
  
  const margin = { top: 40, right: 60, bottom: 40, left: 60 };
  const innerWidth = width - margin.left - margin.right;
  const innerHeight = height - margin.top - margin.bottom;
  
  const titleText = 'Monthly Global Land-Surface Temperature';
  const titleXAxisPos = innerWidth / 2;
  const titleYAxisPos = 10;
  
  const subtitleText = `${d3.min(dataset, xValue)} - ${d3.max(dataset, xValue)}: base temperature ${baseTemperature}℃`;
  const subtitleYAxisPos = titleYAxisPos + 22;
  
  // Initiate a svg canvas
  const svg = d3.select('body')
    .append('svg')
    .style('height', height)
    .style('width', width)
  
  // Initiate a heat map
  const heatmap = svg.append('g')
    .attr('transform', `translate(${margin.left}, ${margin.top})`);
  
  // Establish a scale
  const xScale = d3.scaleTime()
    .domain([d3.min(dataset, xValue), d3.max(dataset, xValue)])
    .range([0, innerWidth]);
  
  const yScale = d3.scaleTime()
    .domain([d3.min(dataset, yValue), d3.max(dataset, yValue)])
    .range([0, innerHeight]);
  
  // Create axes
  const xAxis = d3.axisBottom(xScale).tickFormat(d => d3.timeFormat('%Y')( new Date(0).setFullYear(d) ));
  const yAxis = d3.axisLeft(yScale).tickFormat(d => d3.timeFormat('%M')( new Date(0).setMonth(d) ));
  
  heatmap.append('g')
       .attr('id', 'x-axis')
       .attr('transform', `translate(0, ${innerHeight})`)
       .call(xAxis);
    
  heatmap.append('g')
    .attr('id', 'y-axis')
    .call(yAxis);
  
  const titleSection = heatmap.append('g')
      .attr('text-anchor', 'middle')
    
  titleSection.append('text')
    .attr('id', 'title')
    .attr('x',  titleXAxisPos)
    .attr('y', titleYAxisPos)
    .style('font-size', '1.5em')
    .style('font-weight', 'bold')
    .text(titleText);
    
  titleSection.append('text')
    .attr('id', 'subtitle')
    .attr('x', titleXAxisPos)
    .attr('y', subtitleYAxisPos)
    .style('font-size', '1.2em')
    .text(subtitleText);
  
  
};

document.addEventListener('DOMContentLoaded', function() {
  const request = new XMLHttpRequest();
  request.open('GET', 'https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/global-temperature.json', true);
  request.send();
  request.onload = function () {
    let json = JSON.parse(request.responseText);
    let baseTemperature = json.baseTemperature;
    let dataset = json.monthlyVariance;
    addMonthStrings(dataset);
    render(baseTemperature, dataset);
  };
});
body {
  background-color: rgb(128,128,128);
  font-family: monospace;
}

svg {
  background-color: white;
  position: absolute;
  top: 50%;
  left: 50%;
  -moz-transform: translateX(-50%) translateY(-50%);
  -webkit-transform: translateX(-50%) translateY(-50%);
  transform: translateX(-50%) translateY(-50%);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.0.0/d3.min.js"></script>
<body></body>

1 Ответ

1 голос
/ 05 апреля 2020

Нет необходимости генерировать функцию, конвертирующую номер месяца в полные метки, d3-time-format делает это за вас ..

Спецификатор полного имени месяца в d3.timeFormat равен %B (источник: документация формата d3-time .

const yAxis = d3.axisLeft(yScale)
                .tickFormat(d => d3.timeFormat('%B')( new Date(0).setMonth(d-1) ));

Поскольку месяцы в javascript датируются go между 0 и 11, нам нужно вычесть 1 из d, что происходит между 1 и 12.

Приведенный ниже фрагмент иллюстрирует решение.

Было сделано несколько других модификаций, чтобы сделать диаграмму видимой в наборе firefox:

  • svg ширина и высота как attr, а не style
  • удалить жестко CSS позиционирование.

const render = (baseTemperature, dataset) => {
  const width = 960;
  const height = 500;
  
  const xValue = d => d['year'];
  const yValue = d => d['month'];
  const variance = d => Math.round10(d['variance'], -1);
  const currTemp = d => Math.round10(baseTemperature - d['variance'], -1);
  
  const margin = { top: 40, right: 60, bottom: 40, left: 60 };
  const innerWidth = width - margin.left - margin.right;
  const innerHeight = height - margin.top - margin.bottom;
  
  const titleText = 'Monthly Global Land-Surface Temperature';
  const titleXAxisPos = innerWidth / 2;
  const titleYAxisPos = 10;
  
  const subtitleText = `${d3.min(dataset, xValue)} - ${d3.max(dataset, xValue)}: base temperature ${baseTemperature}℃`;
  const subtitleYAxisPos = titleYAxisPos + 22;
  
  // Initiate a svg canvas
  const svg = d3.select('body')
    .append('svg')
    .attr('height', height)
    .attr('width', width)
  
  // Initiate a heat map
  const heatmap = svg.append('g')
    .attr('transform', `translate(${margin.left}, ${margin.top})`);
  
  // Establish a scale
  const xScale = d3.scaleTime()
    .domain([d3.min(dataset, xValue), d3.max(dataset, xValue)])
    .range([0, innerWidth]);
  
  const yScale = d3.scaleTime()
    .domain([d3.min(dataset, yValue), d3.max(dataset, yValue)])
    .range([0, innerHeight]);
  
  // Create axes
  const xAxis = d3.axisBottom(xScale).tickFormat(d => d3.timeFormat('%Y')( new Date(0).setFullYear(d) ));
  const yAxis = d3.axisLeft(yScale).tickFormat(d => d3.timeFormat('%B')( new Date(0).setMonth(d-1) ));
  
  heatmap.append('g')
       .attr('id', 'x-axis')
       .attr('transform', `translate(0, ${innerHeight})`)
       .call(xAxis);
    
  heatmap.append('g')
    .attr('id', 'y-axis')
    .call(yAxis);
  
  const titleSection = heatmap.append('g')
      .attr('text-anchor', 'middle')
    
  titleSection.append('text')
    .attr('id', 'title')
    .attr('x',  titleXAxisPos)
    .attr('y', titleYAxisPos)
    .style('font-size', '1.5em')
    .style('font-weight', 'bold')
    .text(titleText);
    
  titleSection.append('text')
    .attr('id', 'subtitle')
    .attr('x', titleXAxisPos)
    .attr('y', subtitleYAxisPos)
    .style('font-size', '1.2em')
    .text(subtitleText);
  
  
};

document.addEventListener('DOMContentLoaded', function() {
  const request = new XMLHttpRequest();
  request.open('GET', 'https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/global-temperature.json', true);
  request.send();
  request.onload = function () {
    let json = JSON.parse(request.responseText);
    let baseTemperature = json.baseTemperature;
    let dataset = json.monthlyVariance;
    render(baseTemperature, dataset);
  };
});
body {
  background-color: rgb(128,128,128);
  font-family: monospace;
}

svg {
  background-color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.0.0/d3.min.js"></script>
<body></body>
...