如何为点刻度实现反转功能?

时间:2016-11-13 12:07:12

标签: javascript d3.js d3v4

我正在尝试为双线图表添加工具提示。

但是,我使用scalePoint来绘制我的图表,而不是使用timeScale或scaleLinear。

我试图达到以下效果: 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 个答案:

答案 0 :(得分:12)

你是对的,点数比例没有invert。但是您可以创建自己的函数来获取给定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>