d3.js v4 brushY - не может изменить ширину наложения

Я пытался преобразовать этот проект с параллельными координатами из d3 V3 в V4. Проблема возникает, когда я пытаюсь применить чистку по оси Y для каждого измерения.

Я не могу изменить ширину наложения, которое применяется при чистке. Он всегда имеет ширину 1000 единиц. Это происходит, как только я применяю чистку.

Это код, который я до сих пор:

// main.js
var margin = { top: 30, right: 10, bottom: 10, left: 40 },
    width = 1000 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

// The first element in domain will be mapped to the first point, the second domain value to the second point, and so on.
var x = d3.scalePoint()
    .range([0, width])

var y = {}; // Store linear scales for each dimension here!

var line = d3.line();     // https://github.com/d3/d3-shape#line
var axis = d3.axisLeft();
var background;
var foreground;

var dragging = {};
var dimensions = {};

// Create the main svg
var svg = d3.select("body").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 + ")");


d3.csv("cars.csv", function (error, cars) {
    if (error) throw error;

    //// ==== Set Dimensions START ==== ////
    // d3.keys will get the field "names": { cylinders: 8 } cylinders is the key in this case. All the keys will be recieved!
    // For each car variable! d is the variable
    dimensions = d3.keys(cars[0]).filter(function (d) {
        if (d === "name") return false; // Exclude the dimension "name"
        return true;
    });
    // Set the x-axis domain to the dimensions
    x.domain(dimensions);

    // Create a linear y scale for each dimension.
    dimensions.forEach(function (d) {
        y[d] = d3.scaleLinear()
            .domain(d3.extent(cars, function (data) {
                // Return each cars value for specfied dimension d.
                return +data[d];
            }))
            .range([height, 0]);
    })
    //// ==== Set Dimensions END ==== ////

    //// ==== Draw Lines START ==== ////
    background = svg.append("g")
            .attr("class", "background")
            .selectAll("path")
            .data(cars).enter()
        .append("path")
            .attr("d", path)
    foreground = svg.append("g")
            .attr("class", "foreground")
            .selectAll("path")
            .data(cars).enter()
        .append("path")
            .attr("d", path)
    //// ==== Draw Lines END ==== ////

    //// ==== Draw Axis START ==== ////
    var g = svg.selectAll(".dimension")
            .data(dimensions).enter() // g's data is the dimensions
        .append("g")
            .attr("class", "dimension")
            // Give the axis it's propper x pos
            .attr("transform", function(d) {return "translate("+x(d)+ ")"; });
    g.append("g") // The Axis
        .attr("class", "axis")
        .each(function(d) { d3.select(this).call(axis.scale(y[d])); });
    g.append("text") // Axis Label
        .attr("class", "title")
        .style("text-anchor", "middle")
        .attr("y", -10)
        .attr("font-size", 15)
        .text(function(d) { return d; });
    //// ==== Draw Axis END ==== ////

    //// ==== Axis dragging START ==== ////
    g.call(d3.drag()
        .on("start", function(d) {
            dragging[d] = x(d);
            background.attr("visibility", "hidden");
        })
        .on("drag", function(d) {
            // Make sure the dragging is within the range.
            dragging[d] = Math.min(width, Math.max(0, d3.event.x));
            foreground.attr("d", path) // Redraw the lines when draging an axis
            dimensions.sort(function(a,b) {return xPosition(a) - xPosition(b)});
            // Set the domain to the new order of the dimension
            x.domain(dimensions);
            // Translate the axis to mouse position
            g.attr("transform", function(d) { return "translate("+ xPosition(d) +")"; 
        })
    })
    .on("end", function(d) {
        delete dragging[d];
        d3.select(this)
                .transition().duration(200)
                .attr("transform", "translate("+x(d)+")");
        foreground
                .transition().duration(200)
                .attr("d", path)
        background
                .attr("d", path)
                .transition().delay(200).duration(0)
                .attr("visibility", null);
    }));
    //// ==== Axis dragging END ==== ////

    //// ==== Brushing START ==== ////
    g.append("g")
        .attr("class", "brush")
        .each(function(d){
            d3.select(this).call(d3.brushY()
                .on("start", function(){ d3.event.sourceEvent.stopPropagation(); })
                .on("brush", function(d, i){ console.log(d) }))
        })
        .selectAll("rect") 
        .attr("width", 20)  // This part doesn't do anything!
    //// ==== Brushing END ==== ////
});

function xPosition(d) {
  var v = dragging[d]; // This array holds the temporary positions when dragging. 
    if(v == null) return x(d);
    return v;
}

function path(data) {
    return line(dimensions.map(function(dim){
        return [xPosition(dim), y[dim](data[dim])]
    }))
}

Вот скриншот ошибки, если она вам поможет. В нем я почистил крайнее левое измерение, и оно растянулось вправо.

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

Скриншот ошибки

2 ответа

См. Этот пост Как применить масштаб к кисти d3 v4.0?

Я сделал каждую кисть для нескольких измерений в параллельном графике координат так:

dim.brush = d3.brushY()
    .extent([[dim.xPos - 10, this.margins.top], [dim.xPos + 10, this.height - this.margins.top]]);

Хм, это работает, если я применяю правильную ширину в.on("начало") и.on("кисть"). Это похоже на хак, и я не понимаю, почему предыдущее решение работает в V3, а не в V4.

//// ==== Brushing START ==== ////
g.append("g")
        .attr("class", "brush")
        .each(function(d){
            d3.select(this).call(d3.brushY()
                .on("start", function(){ 
                    d3.event.sourceEvent.stopPropagation(); 
                    g.selectAll("rect") 
                        .attr("width", 20)
                        .attr("x", -10)
                })
                .on("brush", function(d, i){ 
                    console.log(d) 
                    g.selectAll("rect") 
                        .attr("width", 20)
                        .attr("x", -10)
                }))
        })
//// ==== Brushing END ==== ////
Другие вопросы по тегам