d3 v4 带 x 和 y 轴的拖动折线图

Posted

技术标签:

【中文标题】d3 v4 带 x 和 y 轴的拖动折线图【英文标题】:d3 v4 drag line chart with x and y axes 【发布时间】:2017-07-31 22:08:17 【问题描述】:

我是 d3.js 的新手。我想用它的点来拖动一个折线图。没有 x 和 y 轴它工作正常。 我用这个例子作为参考:https://bl.ocks.org/mbostock/4342190

对于折线图的轴,该线未正确绘制。请查看下面的 sn-p。

提前致谢。

<!DOCTYPE html>
<svg  ></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

var svg = d3.select("svg"),
    margin = top: 20, right: 20, bottom: 30, left: 50,
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom;
    

let points = d3.range(1, 10).map(function(i) 
    return [i * width / 10, 50 + Math.random() * (height - 100)];
);
var x = d3.scaleLinear()
    .rangeRound([0, width]);

var y = d3.scaleLinear()
    .rangeRound([height, 0]);

var xAxis = d3.axisBottom(x),
    yAxis = d3.axisLeft(y);

var line = d3.line()
    .x(function(d)  return x(d[0]); )
    .y(function(d)  return y(d[1]); );
    
let drag = d3.drag()
        .on('start', dragstarted)
        .on('drag', dragged)
        .on('end', dragended);
        
svg.append('rect')
    .attr('class', 'zoom')
    .attr('cursor', 'move')
    .attr('fill', 'none')
    .attr('pointer-events', 'all')
    .attr('width', width)
    .attr('height', height)
    .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')

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

x.domain(d3.extent(points, function(d)  return d[0]; ));
y.domain(d3.extent(points, function(d)  return d[1]; ));

focus.append("path")
    .datum(points)
    .attr("fill", "none")
    .attr("stroke", "steelblue")
    .attr("stroke-linejoin", "round")
    .attr("stroke-linecap", "round")
    .attr("stroke-width", 1.5)
    .attr("d", line);

focus.selectAll('circle')
    .data(points)
    .enter()
    .append('circle')
    .attr('r', 5.0)
    .attr('cx', function(d)  return x(d[0]);  )
    .attr('cy', function(d)  return y(d[1]); )
    .style('cursor', 'pointer')
    .style('fill', 'steelblue');

focus.selectAll('circle')
        .call(drag);

focus.append('g')
    .attr('class', 'axis axis--x')
    .attr('transform', 'translate(0,' + height + ')')
    .call(xAxis);
    
focus.append('g')
    .attr('class', 'axis axis--y')
    .call(yAxis);

function dragstarted(d) 
    d3.select(this).raise().classed('active', true);


function dragged(d) 
    d3.select(this)
        .attr('cx', d[0] = d3.event.x)
        .attr('cy', d[1] = d3.event.y)
    focus.select('path').attr('d', line);


function dragended(d) 
    d3.select(this).classed('active', false);


</script>

【问题讨论】:

【参考方案1】:

d3.event 保持像素位置,但您的绘图是由用户空间坐标驱动的。因此,您需要将这些像素位置转换为用户空间。您可以使用您的秤invert 方法来做到这一点。

function dragged(d) 
    d[0] = x.invert(d3.event.x); // convert to user-space
    d[1] = y.invert(d3.event.y);
    d3.select(this)
        .attr('cx', x(d[0])) // back to pixels
        .attr('cy', y(d[1]))
    focus.select('path').attr('d', line); //line does pixel conversion too

运行代码:

<!DOCTYPE html>
<svg  ></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

var svg = d3.select("svg"),
    margin = top: 20, right: 20, bottom: 30, left: 50,
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom;
    

let points = d3.range(1, 10).map(function(i) 
    return [i * width / 10, 50 + Math.random() * (height - 100)];
);
var x = d3.scaleLinear()
    .rangeRound([0, width]);

var y = d3.scaleLinear()
    .rangeRound([height, 0]);

var xAxis = d3.axisBottom(x),
    yAxis = d3.axisLeft(y);

var line = d3.line()
    .x(function(d)  return x(d[0]); )
    .y(function(d)  return y(d[1]); );
    
let drag = d3.drag()
        .on('start', dragstarted)
        .on('drag', dragged)
        .on('end', dragended);
        
svg.append('rect')
    .attr('class', 'zoom')
    .attr('cursor', 'move')
    .attr('fill', 'none')
    .attr('pointer-events', 'all')
    .attr('width', width)
    .attr('height', height)
    .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')

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

x.domain(d3.extent(points, function(d)  return d[0]; ));
y.domain(d3.extent(points, function(d)  return d[1]; ));

focus.append("path")
    .datum(points)
    .attr("fill", "none")
    .attr("stroke", "steelblue")
    .attr("stroke-linejoin", "round")
    .attr("stroke-linecap", "round")
    .attr("stroke-width", 1.5)
    .attr("d", line);

focus.selectAll('circle')
    .data(points)
    .enter()
    .append('circle')
    .attr('r', 5.0)
    .attr('cx', function(d)  return x(d[0]);  )
    .attr('cy', function(d)  return y(d[1]); )
    .style('cursor', 'pointer')
    .style('fill', 'steelblue');

focus.selectAll('circle')
        .call(drag);

focus.append('g')
    .attr('class', 'axis axis--x')
    .attr('transform', 'translate(0,' + height + ')')
    .call(xAxis);
    
focus.append('g')
    .attr('class', 'axis axis--y')
    .call(yAxis);

function dragstarted(d) 
    d3.select(this).raise().classed('active', true);


function dragged(d) 
    d[0] = x.invert(d3.event.x);
    d[1] = y.invert(d3.event.y);
    d3.select(this)
        .attr('cx', x(d[0]))
        .attr('cy', y(d[1]))
    focus.select('path').attr('d', line);


function dragended(d) 
    d3.select(this).classed('active', false);


</script>

【讨论】:

以上是关于d3 v4 带 x 和 y 轴的拖动折线图的主要内容,如果未能解决你的问题,请参考以下文章

d3.js带圆圈的实时折线图

Android MPAndroidChart 折线图设置哪些属性?

echars 折线图Y轴

C# Devexpress 画折线图 需要X轴范围始终是0到100,而具体的值会按照百分比对应这个0到100的坐标值。

echarts 折线图x,y轴的刻度字体颜色怎么改??

kibana 折线图 (Line) --- 2022-04-03