Как я могу реализовать функцию инвертирования для шкалы баллов?

Я пытаюсь добавить всплывающую подсказку для моего графика с двумя линейными диаграммами.

Однако вместо использования timeScale или scaleLinear для построения графика я использовал scalePoint.

Я пытаюсь добиться следующего эффекта: https://bl.ocks.org/mbostock/3902569

this.x  = d3.scalePoint().range([ this.margin.left, this.width - this.margin.right ]);
this.xAxis      = d3.axisBottom(this.x);
this.x.domain(
       this.dataArray.map(d => {
       return this.format(d[ 'year' ]);
}));

Вот моя функция наведения мыши,

function mousemove() {
            //d3.mouse(this)[ 0 ]
            //x.invert

            var x0 = d3.mouse(this)[ 0 ],
                i  = bisectDate(data, x0, 1),
                d0 = data[ i - 1 ],
                d1 = data[ i ],
                d  = x0 - d0.year > d1.year - x0 ? d1 : d0;

            console.log(x0);
            // focus.attr("transform", "translate(" + x(format(d.year)) + "," + y(d.housing_index_change) + ")");
            // focus.select("text").text(d.housing_index_change);
        }

Поскольку я использую scalePoint, очевидно, что нет функции инвертирования для сопоставления координат с моими данными. и я получаю только первый элемент в массиве, и это единственный отображаемый элемент независимо от положения мыши.

Итак, мой вопрос, как я могу реализовать функцию инвертирования здесь, все еще используя scalePoint?

Спасибо:)

1 ответ

Решение

Вы правы, для шкалы баллов нет инверсии. Но вы можете создать свою собственную функцию, чтобы получить соответствующий домен заданной позиции x:

function scalePointPosition() {
    var xPos = d3.mouse(this)[0];
    var domain = xScale.domain(); 
    var range = xScale.range();
    var rangePoints = d3.range(range[0], range[1], xScale.step())
    var yPos = domain[d3.bisect(rangePoints, xPos) -1];
    console.log(yPos);
}

Пошаговое объяснение

Во-первых, мы получаем x положение мыши.

var xPos = d3.mouse(this)[0];

Затем, в зависимости от диапазона и домена вашей шкалы...

var domain = xScale.domain(); 
var range = xScale.range();

... мы создаем массив со всеми шагами в шкале точек, используя d3.range:

var rangePoints = d3.range(range[0], range[1], xScale.step())

Наконец, мы получаем соответствующий домен, используя bisect:

var yPos = domain[d3.bisect(rangePoints, xPos) -1];

Проверить console.log в этой демонстрации:

var data = [{
    A: "groupA",
    B: 10
}, {
    A: "groupB",
    B: 20
}, {
    A: "groupC",
    B: 30
}, {
    A: "groupD",
    B: 10
}, {
    A: "groupE",
    B: 17
}]

var width = 500,
    height = 200;

var svg = d3.selectAll("body")
    .append("svg")
    .attr("width", width)
    .attr("height", height);

var color = d3.scaleOrdinal(d3.schemeCategory10)
    .domain(data.map(function(d) {
        return d.A
    }));

var xScale = d3.scalePoint()
    .domain(data.map(function(d) {
        return d.A
    }))
    .range([50, width - 50])
    .padding(0.5);

var yScale = d3.scaleLinear()
    .domain([0, d3.max(data, function(d) {
        return d.B
    }) * 1.1])
    .range([height - 50, 10]);

var circles = svg.selectAll(".circles")
    .data(data)
    .enter()
    .append("circle")
    .attr("r", 8)
    .attr("cx", function(d) {
        return xScale(d.A)
    })
    .attr("cy", function(d) {
        return yScale(d.B)
    })
    .attr("fill", function(d) {
        return color(d.A)
    });

var xAxis = d3.axisBottom(xScale);
var yAxis = d3.axisLeft(yScale);

svg.append("g").attr("transform", "translate(0,150)")
    .attr("class", "xAxis")
    .call(xAxis);

svg.append("g")
    .attr("transform", "translate(50,0)")
    .attr("class", "yAxis")
    .call(yAxis);

svg.append("rect")
    .attr("opacity", 0)
    .attr("x", 50)
    .attr("width", width - 50)
    .attr("height", height)
    .on("mousemove", scalePointPosition);

function scalePointPosition() {
    var xPos = d3.mouse(this)[0];
    var domain = xScale.domain();
    var range = xScale.range();
    var rangePoints = d3.range(range[0], range[1], xScale.step())
    var yPos = domain[d3.bisect(rangePoints, xPos) - 1];
    console.log(yPos);
}
.as-console-wrapper { max-height: 20% !important;}
<script src="https://d3js.org/d3.v4.min.js"></script>

Другие вопросы по тегам