d3 v5 линии и круги нарисованы вне прямоугольника при увеличении или панорамировании - PullRequest
0 голосов
/ 04 февраля 2020

Я пытаюсь реализовать масштабирование и панорамирование на d3 с помощью javascript. Кажется, что линии и круги нарисованы за пределами области, которую я хотел бы, чтобы они просто появились. У меня проблемы с визуализацией, что может быть не так. Вот все js.

(()=> {

// set the dimensions and margins of the graph
var margin = {top: 30, right: 30, bottom: 70, left: 60},
    width = 400 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom
    tipDelvs = d3.tip()
    .attr('class', 'd3-tip')
    .offset([-5, 0])
    .html(function(d) { return "DAY: " + d.DIA + "<br/>PO: " + d.PO_ID})
    tipOpen = d3.tip()
    .attr('class', 'd3-tip')
    .offset([-5, 0])
    .html(function(d) { return "DAY: " + d.DIA + "<br/>PO: " + d.PO_ID})

var files = ["url1", 'url2'];

var promises = [];

files.forEach(function(url) {
    promises.push(d3.json(url))
});

Promise.all(promises).then(function(data) {

tipAvgDelvs = d3.tip()
  .attr('class', 'd3-tip')
  .offset([-5, 0])
  .html(function(d) { return "AVG DELVS: " + Math.floor(data[1].DailyDelvs)})

d3.select("#dailyDeliveryVolume_spinner").remove();

var maxY = d3.max(data[0].STD2, function(d) { return +d.PO_ID })
var dias = []
for(i = 1; i<=data[0].STD2[0].LAST_DAY; i++){
  dias.push(i)
}
var maxX = d3.max(dias, d => {return d})

var finalSTD = [] // has data

var tempOpen = []
var a = [], b = [], prev;

var finalOpen = [] // has data

var x = d3.scaleLinear()
.domain([1, maxX])
.range([ 0, width ])
//.padding(0.05);

var xAxis = d3.axisBottom(x)
//.tickValues(x.domain().filter(function(d,i){ return !(i%2)}));

var y = d3.scaleLinear()
.domain([0, maxY])
.range([ height, 0]);

var yAxis = d3.axisLeft(y)

// Set the zoom and Pan features: how much you can zoom, on which part, and what to do when there is a zoom
var zoom = d3.zoom()
.scaleExtent([1, 3])  // This control how much you can unzoom (x0.5) and zoom (x20)
.extent([[x(1), y(maxY)], [x(maxX), y(0)]])
.translateExtent([[x(1), 0], [x(maxX), y(0)]])
.on("zoom", updateChart);

// append the svg object to the body of the page
var svg = d3.select("#dailyDeliveryVolume")
  .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")")
  .call(tipDelvs)
  .call(tipOpen)
  .call(zoom)
// now the user can zoom and it will trigger the function called updateChart

var gX = svg.append("g")
  .attr("transform", "translate(0," + height + ")")
  .call(xAxis)

var gY = svg.append("g")
  .call(yAxis)

// Add a clipPath: everything out of this area won't be drawn.
var clip = svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("width", width )
.attr("height", height )
.attr("x", 0)
.attr("y", 0);

// This add an invisible rect on top of the chart area. This rect can recover pointer events: necessary to understand when the user zoom

svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all")
//.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')

// Create the scatter variable: where both the circles and the brush take place
var scatter = svg.append('g')
.attr("clip-path", "url(#clip)")

var lineDelvs = d3.line()
.x(function(d) { return x(d.DIA); })
.y(function(d) { return y(+d.PO_ID); })

// Bars
scatter.attr("class", "scatter").append("path")
  //.datum(data[0].STD2)
  .datum(finalSTD)
  .attr('class', 'line')
  .attr("fill", "none")
  .attr("stroke", "lightgreen") 
  .attr("stroke-width", 1.5)
  .attr("d", lineDelvs)

scatter.selectAll(".circle")
     //.data(data[0].STD2)
     .data(finalSTD)
     .enter()
     .append("svg:circle")
     .attr("class", "circle")
     .attr("fill", "lightgreen")
     .attr("cx", function (d, i) {return x(d.DIA);})
     .attr("cy", function (d, i) {return y(d.PO_ID);})
     .attr("r", 5)
     .on('mouseover', tipDelvs.show)
     .on('mouseout', tipDelvs.hide)

var lineOpen = d3.line()
.x(function(d) { return x(d.DIA); })
.y(function(d) { return y(+d.PO_ID); })

scatter.append("path")
  //.datum(data[0].OPEN2)
  .datum(finalOpen)
  .attr('class', 'line')
  .attr("fill", "none")
  .attr("stroke", "white")
  .attr("stroke-width", 1.5)
  .attr("d", lineOpen)

scatter.selectAll(".circule")
    //.data(data[0].OPEN2)
    .data(finalOpen)
    .enter()
    .append("svg:circle")
    .attr("class", "circle")
    .attr("fill", "lightgrey")
    .attr("cx", function (d, i) {return x(d.DIA);})
    .attr("cy", function (d, i) {return y(d.PO_ID);})
    .attr("r", 5)
    .on('mouseover', tipOpen.show)
    .on('mouseout', tipOpen.hide)


var deltaTemp = []
//for (i=0; i<data[0].STD2.length; i++){
//  deltaTemp.push(data[0].STD2[i].PO_ID - data[0].OPEN2[i].PO_ID)
for (i=0; i<finalSTD.length; i++){
  deltaTemp.push(finalSTD[i].PO_ID - finalOpen[i].PO_ID)
}
const average = arr => arr.reduce( ( p, c ) => p + c, 0 ) / arr.length;
var delta = average(deltaTemp)

tipAvgDelta = d3.tip()
    .attr('class', 'd3-tip')
    .offset([-5, 0])
    .html(function(d) { return "AVG DELTA: " + Math.floor(delta)})

svg = d3.select("#dailyDeliveryVolume").select('g').call(tipAvgDelta).call(tipAvgDelvs)

scatter.append('line')
      .attr('class', 'line')
      .style('stroke', 'lightcoral')
      .attr('x1', x(0))
      .attr('y1', y(data[1].DailyDelvs))
      .attr('x2', x(data[0].STD2[0].LAST_DAY))
      .attr('y2', y(data[1].DailyDelvs))

scatter.append('circle')
      .attr("class", "circle")
      .attr("fill", "coral")
      .attr('cx', x(data[0].STD2[0].LAST_DAY))
      .attr('cy', y(data[1].DailyDelvs))
      .attr("r", 5)
      .on("mouseover", tipAvgDelvs.show)
      .on("mouseleave", tipAvgDelvs.hide)

scatter.append('line')
    .attr('class', 'line')
    .style('stroke', 'yellow')
    .attr('x1', x(0))
    .attr('y1', y(delta))
    .attr('x2', x(data[0].STD2[0].LAST_DAY))
    .attr('y2', y(delta))

scatter.append('circle')
    .attr("class", "circle")
    .attr("fill", "lightyellow")
    .attr('cx', x(data[0].STD2[0].LAST_DAY))
    .attr('cy', y(delta))
    .attr("r", 5)
    .on("mouseover", tipAvgDelta.show)
    .on("mousemove", tipAvgDelta.show)
    .on("mouseleave", tipAvgDelta.hide)

// A function that updates the chart when the user zoom and thus new boundaries are available
function updateChart() {
  svg.selectAll(".scatter")
   .attr("transform", d3.event.transform);
  d3.selectAll('.line').style("stroke-width", 2/d3.event.transform.k);
  gX.call(xAxis.scale(d3.event.transform.rescaleX(x)));
  gY.call(yAxis.scale(d3.event.transform.rescaleY(y)));
}

svg.append("text")
  .text("Delivered")
  .attr("fill", "lightgreen")
  .attr("x", 240)
  .attr("y", 30)

svg.append("text")
  .text("New")
  .attr("fill", "white")
  .attr("x", 240)
  .attr("y", 45)

})  
})()

Я скопировал детали и детали из разных реализаций, чтобы получить окончательный результат

enter image description here

Однако логика c для масштабирования и панорамирования работает не так, как я ожидал.

enter image description here

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

Когда я проверяю страницу, пределом является svg. Я звоню в zoom на svg: g, но не уверен, что это как-то связано с этим. Тем не менее, я попытался вызвать zoom на 'rect', но у меня были те же результаты.

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

...