D3.js : Как добиться плавного перехода по оси x на графике временных рядов за каждую секунду?

#javascript #d3.js

#javascript #d3.js

Вопрос:

Я пытаюсь добиться плавного и непрерывного перехода моей оси x на графике временных рядов. Пока что он переходит, останавливается, переходы, остановки.. каждую секунду; мое временное окно составляет 10 секунд.

Более того, переходы начинаются и заканчиваются за пределами моей оси x. Есть ли простое исправление? Спасибо за ваше внимание! Вот мой рабочий пример:

 ////////////////////////////////////////////////////////////
////////////////////// Set-up  /////////////////////////////
////////////////////////////////////////////////////////////

const margin = {
  left: 80,
  right: 80,
  top: 30,
  bottom: 165
};

//Actual graph smaller than svg container 
var width = $('#chart').width() - margin.left - margin.right;
var height = $('#chart').height() - margin.top - margin.bottom;

//yAxis
const yDomain = [0, 70];
const yTickValues = [0, 10, 20, 30, 40, 50, 60, 70];

const TIME_INTERVAL = 1000;

//xAxis domain-> 10 seconds 
const originalTime1 = "1970-01-01T00:00:00",
  originalTime2 = "1970-01-01T00:00:10";

var date1 = new Date(originalTime1).getTime(),
  date2 = new Date(originalTime2).getTime();

////////////////////////////////////////////////////////////
///////////////////////// SVG //////////////////////////////
//////////////////////////////////////////////////////////// 

const svg = d3.select("#chart")
  .append("svg")
  .attr("width", width   margin.left   margin.right)
  .attr("height", height   margin.top   margin.bottom);

const g = svg.append("g")
  .attr("transform", "translate("   margin.left   ", "   margin.top   ")");

////////////////////////////////////////////////////////////
///////////////////// Axes amp; Scales ////////////////////////
////////////////////////////////////////////////////////////

var xAxisGroup = g.append("g")
  .attr("class", "x-axis");

var yAxisGroup = g.append("g")
  .attr("class", "y-axis");

//Dynamic
var xScale = d3.scaleTime();

//Fixed
var yScale = d3.scaleLinear()
  .domain([yDomain[0], yDomain[1]])
  .range([height - margin.bottom, 0]);

const xAxis = d3.axisBottom(xScale)
  .ticks(d3.timeSecond.every(1))
  .tickSizeInner(15)
  .tickFormat(d3.timeFormat("%M:%S"));

const yAxis = d3.axisLeft()
  .scale(yScale)
  .tickValues(yTickValues)
  .tickFormat(d3.format(".0f"));

////////////////////////////////////////////////////////////
/////////////////////// Function ///////////////////////////
////////////////////////////////////////////////////////////

function draw() {

  //Update xAxis scale
  xScale.domain([date1, date2])
    .range([0, width]);

  //Call axes
  xAxisGroup.attr("transform", "translate(0,"   (height - margin.bottom)   ")")
    .transition().duration(1000)
    .call(xAxis);

  yAxisGroup.call(yAxis);

  date1  = TIME_INTERVAL;
  date2  = TIME_INTERVAL;

};

////////////////////////////////////////////////////////////
///////////////////////// Main /////////////////////////////
////////////////////////////////////////////////////////////

draw();
setInterval(draw, 1000);  
 .x-axis,
.y-axis {
  font-size: 0.8em;
  stroke-width: 0.06em;
}

#chart {
  width: 600px;
  height: 500px;
}  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="chart"></div>  

Ответ №1:

Используйте .transition.ease(d3.easeLinear) , чтобы сделать весь переход линейным. Таким образом, заметного замедления вообще нет.

Для второй части я не смог найти хорошего обходного пути, но простое решение заключается в том, чтобы просто нарисовать белый прямоугольник над областью, которую вы хотите скрыть — в данном случае слева. Я добавил это перед добавлением y группы осей, чтобы это не мешало.

 ////////////////////////////////////////////////////////////
////////////////////// Set-up  /////////////////////////////
////////////////////////////////////////////////////////////

const margin = {
  left: 80,
  right: 80,
  top: 30,
  bottom: 165
};

//Actual graph smaller than svg container 
var width = $('#chart').width() - margin.left - margin.right;
var height = $('#chart').height() - margin.top - margin.bottom;

//yAxis
const yDomain = [0, 70];
const yTickValues = [0, 10, 20, 30, 40, 50, 60, 70];

const TIME_INTERVAL = 1000;

//xAxis domain-> 10 seconds 
const originalTime1 = "1970-01-01T00:00:00",
  originalTime2 = "1970-01-01T00:00:10";

var date1 = new Date(originalTime1).getTime(),
  date2 = new Date(originalTime2).getTime();

////////////////////////////////////////////////////////////
///////////////////////// SVG //////////////////////////////
//////////////////////////////////////////////////////////// 

const svg = d3.select("#chart")
  .append("svg")
  .attr("width", width   margin.left   margin.right)
  .attr("height", height   margin.top   margin.bottom);

const g = svg.append("g")
  .attr("transform", "translate("   margin.left   ", "   margin.top   ")");

////////////////////////////////////////////////////////////
///////////////////// Axes amp; Scales ////////////////////////
////////////////////////////////////////////////////////////

var xAxisGroup = g.append("g")
  .attr("class", "x-axis");

// HACK: draw white rectangle over the fading axis
g.append('rect')
  .attr('fill', 'white')
  .attr('width', margin.left)
  .attr('height', margin.bottom)
  .attr('x', -margin.left)
  .attr('y', height - margin.bottom);

var yAxisGroup = g.append("g")
  .attr("class", "y-axis");

//Dynamic
var xScale = d3.scaleTime();

//Fixed
var yScale = d3.scaleLinear()
  .domain([yDomain[0], yDomain[1]])
  .range([height - margin.bottom, 0]);

const xAxis = d3.axisBottom(xScale)
  .ticks(d3.timeSecond.every(1))
  .tickSizeInner(15)
  .tickFormat(d3.timeFormat("%M:%S"));

const yAxis = d3.axisLeft()
  .scale(yScale)
  .tickValues(yTickValues)
  .tickFormat(d3.format(".0f"));

////////////////////////////////////////////////////////////
/////////////////////// Function ///////////////////////////
////////////////////////////////////////////////////////////

function draw() {

  //Update xAxis scale
  xScale.domain([date1, date2])
    .range([0, width]);

  //Call axes
  xAxisGroup.attr("transform", "translate(0,"   (height - margin.bottom)   ")")
    .transition()
    .duration(1000)

    // See here for the change:
    .ease(d3.easeLinear)
    .call(xAxis);

  yAxisGroup.call(yAxis);

  date1  = TIME_INTERVAL;
  date2  = TIME_INTERVAL;

};

////////////////////////////////////////////////////////////
///////////////////////// Main /////////////////////////////
////////////////////////////////////////////////////////////

draw();
setInterval(draw, 1000);  
 .x-axis,
.y-axis {
  font-size: 0.8em;
  stroke-width: 0.06em;
}

#chart {
  width: 600px;
  height: 500px;
}  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="chart"></div>