SVG路径超出了d3画笔上的图表区域

Nis*_*hth 2 svg d3.js

当我尝试刷线和缩放折线图的一部分时,所选区域的某些部分会在图表外部渲染.

代码和行为再现可以在这个jsbin找到.

单击并拖动以选择一个部分并放大,双击以缩小.

var svg = d3
  .select('body')
  .append('svg')
  .attr('class', 'chart')
  .attr('width', 960)
  .attr('height', 500);
var margin = {
  top: 40,
  right: 40,
  bottom: 40,
  left: 40
};
var width = +svg.attr('width') - margin.left - margin.right;
var height = +svg.attr('height') - margin.top - margin.bottom;
var g = svg
  .append('g')
  .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
var timeParser = d3.timeParse('%Y-%m-%d');
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var brush = d3.brush().on('end', brushended);
var idleTimeout;
var idleDelay = 350;
var x0;
var y0;
var xAxis;
var yAxis;
var line = d3
  .line()
  .x(function(d) {
    return x(d.date);
  })
  .y(function(d) {
    return y(d.price);
  })
  .curve(d3.curveNatural);
var start = new Date();
var end = new Date(start.toDateString());
start.setFullYear(end.getFullYear() - 1);
var startStr = start.toISOString().slice(0, 10);
var endStr = end.toISOString().slice(0, 10);
var url = "https://api.coindesk.com/v1/bpi/historical/close.json?start=" + startStr + "&end=" + endStr;
d3.json(url, function(error, response) {
  var data = Object.keys(response.bpi).map(function(date) {
    return {
      date: timeParser(date),
      price: response.bpi[date]
    };
  });
  x0 = d3.extent(data, function(d) {
    return d.date;
  });
  y0 = d3.extent(data, function(d) {
    return d.price;
  });
  x.domain(x0);
  y.domain(y0);
  xAxis = d3.axisBottom(x);
  yAxis = d3.axisLeft(y);
  g
    .append('g')
    .attr('class', 'axis axis--x')
    .attr('transform', 'translate(0,' + height + ')')
    .call(xAxis);
  g
    .append('g')
    .attr('class', 'axis axis--y')
    .call(yAxis);
  g
    .append('path')
    .attr('class', 'line')
    .datum(data)
    .attr('fill', 'none')
    .attr('stroke', 'steelblue')
    .attr('d', line);
  svg
    .append('g')
    .attr('class', 'brush')
    .call(brush);
});

function brushended() {
  var s = d3.event.selection;
  if (!s) {
    if (!idleTimeout) {
      return (idleTimeout = setTimeout(idled, idleDelay));
    }
    x.domain(x0);
    y.domain(y0);
  } else {
    x.domain([s[0][0] - 40, s[1][0] - 40].map(x.invert, x));
    y.domain([s[1][1] - 40, s[0][1] - 40].map(y.invert, y));
    svg.select('.brush').call(brush.move, null);
  }
  zoom();
}

function idled() {
  idleTimeout = null;
}

function zoom() {
  var t = svg.transition().duration(750);
  svg
    .select('.axis--x')
    .transition(t)
    .call(xAxis);
  svg
    .select('.axis--y')
    .transition(t)
    .call(yAxis);
  svg
    .select('.line')
    .transition(t)
    .attr('d', line);
}
Run Code Online (Sandbox Code Playgroud)
.chart {
  border: 1px solid #bdbdbd;
  box-sizing: border-box;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://unpkg.com/d3@4.12.2/build/d3.min.js"></script>
Run Code Online (Sandbox Code Playgroud)

Ger*_*ado 6

这是预期的行为.最常见的处理方法是使用a <clipPath>.

例如,在您的情况下:

var clipPath = g.append("defs")
    .append("clipPath")
    .attr("id", "clip")
    .append("rect")
    .attr("width", width)
    .attr("height", height);
Run Code Online (Sandbox Code Playgroud)

然后,在你的道路上:

g.append('path')
    //etc...
    .attr("clip-path", "url(#clip)");
Run Code Online (Sandbox Code Playgroud)

这是更新的JSBin:https://jsbin.com/tatuhipevi/1/edit js,output

这里更新的SO片段:

var svg = d3
  .select('body')
  .append('svg')
  .attr('class', 'chart')
  .attr('width', 960)
  .attr('height', 500);
var margin = {
  top: 40,
  right: 40,
  bottom: 40,
  left: 40
};
var width = +svg.attr('width') - margin.left - margin.right;
var height = +svg.attr('height') - margin.top - margin.bottom;
var g = svg
  .append('g')
  .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
var clipPath = g.append("defs")
  .append("clipPath")
  .attr("id", "clip")
  .append("rect")
  .attr("width", width)
  .attr("height", height);
var timeParser = d3.timeParse('%Y-%m-%d');
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var brush = d3.brush().on('end', brushended);
var idleTimeout;
var idleDelay = 350;
var x0;
var y0;
var xAxis;
var yAxis;
var line = d3
  .line()
  .x(function(d) {
    return x(d.date);
  })
  .y(function(d) {
    return y(d.price);
  })
  .curve(d3.curveNatural);
var start = new Date();
var end = new Date(start.toDateString());
start.setFullYear(end.getFullYear() - 1);
var startStr = start.toISOString().slice(0, 10);
var endStr = end.toISOString().slice(0, 10);
var url = "https://api.coindesk.com/v1/bpi/historical/close.json?start=" + startStr + "&end=" + endStr;
d3.json(url, function(error, response) {
  var data = Object.keys(response.bpi).map(function(date) {
    return {
      date: timeParser(date),
      price: response.bpi[date]
    };
  });
  x0 = d3.extent(data, function(d) {
    return d.date;
  });
  y0 = d3.extent(data, function(d) {
    return d.price;
  });
  x.domain(x0);
  y.domain(y0);
  xAxis = d3.axisBottom(x);
  yAxis = d3.axisLeft(y);
  g
    .append('g')
    .attr('class', 'axis axis--x')
    .attr('transform', 'translate(0,' + height + ')')
    .call(xAxis);
  g
    .append('g')
    .attr('class', 'axis axis--y')
    .call(yAxis);
  g
    .append('path')
    .attr('class', 'line')
    .datum(data)
    .attr('fill', 'none')
    .attr('stroke', 'steelblue')
    .attr('d', line)
    .attr("clip-path", "url(#clip)");
  svg
    .append('g')
    .attr('class', 'brush')
    .call(brush);
});

function brushended() {
  var s = d3.event.selection;
  if (!s) {
    if (!idleTimeout) {
      return (idleTimeout = setTimeout(idled, idleDelay));
    }
    x.domain(x0);
    y.domain(y0);
  } else {
    x.domain([s[0][0] - 40, s[1][0] - 40].map(x.invert, x));
    y.domain([s[1][1] - 40, s[0][1] - 40].map(y.invert, y));
    svg.select('.brush').call(brush.move, null);
  }
  zoom();
}

function idled() {
  idleTimeout = null;
}

function zoom() {
  var t = svg.transition().duration(750);
  svg
    .select('.axis--x')
    .transition(t)
    .call(xAxis);
  svg
    .select('.axis--y')
    .transition(t)
    .call(yAxis);
  svg
    .select('.line')
    .transition(t)
    .attr('d', line);
}
Run Code Online (Sandbox Code Playgroud)
.chart {
  border: 1px solid #bdbdbd;
  box-sizing: border-box;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://d3js.org/d3.v4.min.js"></script>
Run Code Online (Sandbox Code Playgroud)

此外,<clipPath>在轴上使用a也是一个好主意.