d3.js - 范围宽度与 svg defs 的轴线不匹配

d3.js - extent width not match axis line with svg defs

我想为带有箭头的轴添加一些扩展。下面的代码基本上可以工作,但是范围箭头的宽度与轴的宽度不匹配!

axis_demo()
function axis_demo() {
  var width = 400
  var height = 100
  var margin = {left:20,top:40,right:80,bottom:20}
  
  var svg = d3.select('body')
  .append('svg')
  .attr('width',width + margin.left + margin.right)
  .attr('height',height + margin.top + margin.bottom)
  .style('border','2px solid red')
      
  var lc = 'grey'
  var lw = 4
  add_defs(svg,lw,lc)
  
  var g = svg.append('g')
  .attr('transform',`translate(${margin.left},${margin.top})`)
  
  add_scalePoint(g,width,height)
  console.log("done")
  function add_scalePoint(g,width,height) {
    var data = [
      {day : 'Mon', value: 10},
      {day : 'Tue', value: 40},
      {day : 'Wed', value: 30},
      {day : 'Thu', value: 60},
      {day : 'Fri', value: 30}
    ];
    var xname = 'day'
    var yname = 'value'
    
    var xdomain = data.map(d => d[xname])
    var xScale = d3.scalePoint()
      .domain(xdomain)
      .range([0, width]);
    
    let xaxis = g.append("g")       
    .attr("class", "xaxis")
    .call(d3.axisBottom(xScale) 
          .tickSizeOuter(0)
          .tickPadding(0))

    xaxis.select('path')
      .attr('stroke-width',lw)
      .attr('stroke',lc)
      .attr('marker-end', 'url(#arrhead)');
    
    xaxis.selectAll('.tick line')
      .attr('stroke',lc)
    
    xaxis.selectAll("text")
    .attr("transform", "rotate(-30)")
    .style("text-anchor", "end");

    g.selectAll('circle')
      .data(data)
      .enter()
      .append('circle')
      .attr('cy',-30)
      .attr('cx', function(d) {
        return xScale(d[xname]);
      })
      .attr('r', 2);
  }
  
  function add_defs(g,lw,lc) {
      var xoff = 10
      var dx = 4
      var dy = 1.5
      var arrpath = ['M',2*lw,dy+2*lw,'l',xoff,0,
         0,dy,dx,-dy,-dx,-dy,0,dy]
      svg
      .append('defs')
      .append('marker')
      .attr('id', 'arrhead')
      .attr('refX', 2*lw)
      .attr('refY', dy+2*lw)
      .attr('markerWidth',xoff + dx + 4*lw )
      .attr('markerHeight', 2*dy + 4*lw)
      .attr('orient', 'auto-start-reverse')
      .append('path')
      .attr('d', arrpath.join(' '))
      .attr('stroke-miterlimit',5)
      .attr('stroke', lc)
      .attr('stroke-width', lw)
      .attr('fill', lc);
  }
  
  function add_circle(g,cx,cy,r) {
    g.append('circle')
    .attr('cx',cx)
    .attr('cy',cy)
    .attr('r',r);
  }
}
 <script src="https://d3js.org/d3.v6.min.js"></script>

省略

.attr('stroke-width', lw)

构建标记时,

或将 lw 替换为 1:

.attr('stroke-width', 1)

axis_demo()
function axis_demo() {
  var width = 400
  var height = 100
  var margin = {left:20,top:40,right:80,bottom:20}
  
  var svg = d3.select('body')
  .append('svg')
  .attr('width',width + margin.left + margin.right)
  .attr('height',height + margin.top + margin.bottom)
  .style('border','2px solid red')
      
  var lc = 'grey'
  var lw = 4
  add_defs(svg,lw,lc)
  
  var g = svg.append('g')
  .attr('transform',`translate(${margin.left},${margin.top})`)
  
  add_scalePoint(g,width,height)
  console.log("done")
  function add_scalePoint(g,width,height) {
    var data = [
      {day : 'Mon', value: 10},
      {day : 'Tue', value: 40},
      {day : 'Wed', value: 30},
      {day : 'Thu', value: 60},
      {day : 'Fri', value: 30}
    ];
    var xname = 'day'
    var yname = 'value'
    
    var xdomain = data.map(d => d[xname])
    var xScale = d3.scalePoint()
      .domain(xdomain)
      .range([0, width]);
    
    let xaxis = g.append("g")       
    .attr("class", "xaxis")
    .call(d3.axisBottom(xScale) 
          .tickSizeOuter(0)
          .tickPadding(0))

    xaxis.select('path')
      .attr('stroke-width',lw)
      .attr('stroke',lc)
      .attr('marker-end', 'url(#arrhead)');
    
    xaxis.selectAll('.tick line')
      .attr('stroke',lc)
    
    xaxis.selectAll("text")
    .attr("transform", "rotate(-30)")
    .style("text-anchor", "end");

    g.selectAll('circle')
      .data(data)
      .enter()
      .append('circle')
      .attr('cy',-30)
      .attr('cx', function(d) {
        return xScale(d[xname]);
      })
      .attr('r', 2);
  }
  
  function add_defs(g,lw,lc) {
      var xoff = 10
      var dx = 4
      var dy = 1.5
      var arrpath = ['M',2*lw,dy+2*lw,'l',xoff,0,
         0,dy,dx,-dy,-dx,-dy,0,dy]
      svg
      .append('defs')
      .append('marker')
      .attr('id', 'arrhead')
      .attr('refX', 2*lw)
      .attr('refY', dy+2*lw)
      .attr('markerWidth',xoff + dx + 4*lw )
      .attr('markerHeight', 2*dy + 4*lw)
      .attr('orient', 'auto-start-reverse')
      .append('path')
      .attr('d', arrpath.join(' '))
      .attr('stroke-miterlimit',5)
      .attr('stroke', lc)
      .attr('stroke-width', 1)
      .attr('fill', lc);
  }
  
  function add_circle(g,cx,cy,r) {
    g.append('circle')
    .attr('cx',cx)
    .attr('cy',cy)
    .attr('r',r);
  }
}
 <script src="https://d3js.org/d3.v6.min.js"></script>