【问题标题】:How to add grid lines to a Chart in Javascript如何在 Javascript 中向图表添加网格线
【发布时间】:2021-04-29 18:51:39
【问题描述】:

我是 Javascript 新手,通过探索各种网站,我创建了一个可拖动的点折线图。数据点是可移动的,连接点的线是不可见的。数据点只会垂直移动。我想在这个图表上有网格线。我尝试过但未能实现。有人可以帮我在此图表中添加网格线吗?我已经附上了我构建的代码。

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.0/d3.min.js"></script>
<!DOCTYPE html>

<style>
.grid .tick {
    stroke: lightgrey;
    opacity: 0.7;
}
.grid path {
      stroke-width: 0;
}

.grid .tick {
    stroke: lightgrey;
    opacity: 0.7;
}
.grid path {
      stroke-width: 0;
}

</style>

<svg width="500" height="350"></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;

function make_x_axis() {        
    return d3.svg.axis()
        .scale(x)
         .orient("bottom")
         .ticks(5)
}

function make_y_axis() {        
    return d3.svg.axis()
        .scale(y)
        .orient("left")
        .ticks(5)
}   

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 + ')')
    
svg.append("g")         
        .attr("class", "grid")
        .attr("transform", "translate(0," + height + ")")
        .call(make_x_axis()
            .tickSize(-height, 0, 0)
            .tickFormat("")
        )

svg.append("g")         
    .attr("class", "grid")
    .call(make_y_axis()
    .tickSize(-width, 0, 0)
    .tickFormat("")
         )

 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", "white")
    .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>

【问题讨论】:

  • 我认为您在第一句话中指的是 JavaScript(不是 Java)。您能否分享您已经尝试过的内容,因为此代码仅来自 D3 Observable
  • 嗨,艾丽西亚,感谢您的回复。是的,它是一个 D3 Observable 代码,这就是我的要求。我已经编辑了代码以添加我尝试过的网格线。

标签: javascript svg d3.js


【解决方案1】:

您用来附加网格的部分来自 d3.js 的 v3。 d3v4 添加了d3.axisLeft()d3.axisBottom() 等。见this post

另外,您用于网格的translate 坐标不正确,我已经调整了一些值,使其适合图表。

这是一个工作示例:

<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.0/d3.min.js"></script>-->
<!DOCTYPE html>

<style>

.grid .tick {
    stroke: lightgrey;
    opacity: 0.7;
}
.grid path {
      stroke-width: 0;
}

.grid .tick {
    stroke: lightgrey;
    opacity: 0.7;
}
.grid path {
      stroke-width: 0;
}

</style>

<svg width="500" height="350"></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;

function make_x_axis() {
    return d3.axisBottom(x)
        // .scale(x)
        //  .orient("bottom")
         .ticks(5)
}

function make_y_axis() {
    return d3.axisLeft(y)
        // .scale(y)
        // .orient("left")
        .ticks(5)
}

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 + ')')



// svg.append("g")
//         .attr("class", "grid")
//         .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
//         .call(make_x_axis()
//             .tickSize(-height, 0, 0)
//             .tickFormat("")
//         )
//
// svg.append("g")
//     .attr("class", "grid")
//     .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
//     // .attr("transform", "translate(0," + (height + margin.top) + ")")
//     .call(make_y_axis()
//     .tickSize(-width, 0, 0)
//     .tickFormat("")
//          )
svg.append("g")
      .attr("class", "grid")
      .attr("transform", `translate(${margin.left}, ${height + margin.top})`)
      .call(make_x_axis()
          .tickSize(-height)
          .tickFormat("")
      )

  // add the Y gridlines
  svg.append("g")
      .attr("class", "grid")
      .attr("transform", `translate(${margin.left}, ${margin.top})`)
      .call(make_y_axis()
          .tickSize(-width)
          .tickFormat("")
      )

 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", "white")
    .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>

如果您想知道为什么线条“断”,那是因为最适合的白色线条与网格重叠。

线路显示:

<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.0/d3.min.js"></script>-->
<!DOCTYPE html>

<style>

.grid .tick {
    stroke: lightgrey;
    opacity: 0.7;
}
.grid path {
      stroke-width: 0;
}

.grid .tick {
    stroke: lightgrey;
    opacity: 0.7;
}
.grid path {
      stroke-width: 0;
}

</style>

<svg width="500" height="350"></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;

function make_x_axis() {
    return d3.axisBottom(x)
        // .scale(x)
        //  .orient("bottom")
         .ticks(5)
}

function make_y_axis() {
    return d3.axisLeft(y)
        // .scale(y)
        // .orient("left")
        .ticks(5)
}

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 + ')')



// svg.append("g")
//         .attr("class", "grid")
//         .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
//         .call(make_x_axis()
//             .tickSize(-height, 0, 0)
//             .tickFormat("")
//         )
//
// svg.append("g")
//     .attr("class", "grid")
//     .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
//     // .attr("transform", "translate(0," + (height + margin.top) + ")")
//     .call(make_y_axis()
//     .tickSize(-width, 0, 0)
//     .tickFormat("")
//          )
svg.append("g")
      .attr("class", "grid")
      .attr("transform", `translate(${margin.left}, ${height + margin.top})`)
      .call(make_x_axis()
          .tickSize(-height)
          .tickFormat("")
      )

  // add the Y gridlines
  svg.append("g")
      .attr("class", "grid")
      .attr("transform", `translate(${margin.left}, ${margin.top})`)
      .call(make_y_axis()
          .tickSize(-width)
          .tickFormat("")
      )

 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", "black") // modified
    .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>

【讨论】:

  • 非常感谢@Parzival。我的要求不希望在点之间显示线条,所以我将其设为白色。这是完美的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-07
  • 2014-08-22
  • 2019-11-04
  • 1970-01-01
  • 2021-07-12
  • 2021-07-30
相关资源
最近更新 更多