【问题标题】:d3js - How to move x- domain values towards rightd3js - 如何将 x- 域值向右移动
【发布时间】:2017-07-08 16:43:58
【问题描述】:

我正在使用 d3.js 版本 4 制作一张图表。 所以我想将条形图的绘图向右移动,如下所示。

通常,条形图从起始位置呈现,如下所示

请帮忙....! Demo fiddle

【问题讨论】:

  • 请分享一些代码,以便我们为您提供帮助。首选jsfiddle
  • @Shiladitya 请在这里找到工作代码jsfiddle.net/L7kjbrfo
  • 小提琴示例看起来不错,它没有反映您所说的问题。
  • @Shiladitya 嘿......是的,图表没有问题,但我希望它像第一张图片......在开始处留下一些空白标记为红线

标签: javascript html css d3.js charts


【解决方案1】:

在 D3 v4.x 中,没有本地方法可以设置带刻度中第一个刻度之前的绝对填充量。

不过,如果您接受 hacky 解决方案,则有几个 hacks

其中一个 hacky 解决方案是在真实域之前简单地添加假值...

xScale.domain(["foo", "bar", "baz"].concat(stackedData[0].map(function(d) {
    return d.data.day;
})));

...并且仅在轴中显示真实域:

xAxis.scale(xScale)
    .tickValues(stackedData[0].map(function(d) {
        return d.data.day;
    }));

结果如下:

var self = this;
self.plannedHours = 80;
self.averagePlannedHours = 70;
self.averagPlannedItems = 7;
self.isStoryPoints = false;
self.availableHours = 0;
self.data = [{
  "day": "Mon",
  "avgPlannedHours": 70,
  "overPlannedHours": 80,
  "doneWork": 0
}, {
  "day": "Tue",
  "avgPlannedHours": 70,
  "overPlannedHours": 80,
  "doneWork": 30
}, {
  "day": "Wed",
  "avgPlannedHours": 70,
  "overPlannedHours": 90,
  "doneWork": 35
}, {
  "day": "Thu",
  "avgPlannedHours": 70,
  "overPlannedHours": 90,
  "doneWork": 50
}, {
  "day": "Fri",
  "avgPlannedHours": 70,
  "overPlannedHours": 90,
  "doneWork": 55
}, {
  "day": "Sat",
  "avgPlannedHours": 0,
  "overPlannedHours": 0,
  "doneWork": 0
}, {
  "day": "Sun",
  "avgPlannedHours": 0,
  "overPlannedHours": 0,
  "doneWork": 0
}, {
  "day": "Mon1",
  "avgPlannedHours": 70,
  "overPlannedHours": 80,
  "doneWork": 0
}, {
  "day": "Tue1",
  "avgPlannedHours": 70,
  "overPlannedHours": 80,
  "doneWork": 30
}, {
  "day": "Wed1",
  "avgPlannedHours": 70,
  "overPlannedHours": 90,
  "doneWork": 35
}, {
  "day": "Thu1",
  "avgPlannedHours": 70,
  "overPlannedHours": 90,
  "doneWork": 50
}, {
  "day": "Fri1",
  "avgPlannedHours": 70,
  "overPlannedHours": 90,
  "doneWork": 55
}, {
  "day": "Sat1",
  "avgPlannedHours": 0,
  "overPlannedHours": 0,
  "doneWork": 0
}, {
  "day": "Sun1",
  "avgPlannedHours": 0,
  "overPlannedHours": 0,
  "doneWork": 0
}];
self.dataCopy = self.data.slice();
self.normalisedData = [];
normalizeData();

function normalizeData() {
  self.normalisedData = self.data.map(function(data, index) {
    if (self.plannedHours > self.averagePlannedHours) {
      data.overPlannedHours = data.overPlannedHours - data.avgPlannedHours;
    } else if (self.plannedHours < self.averagePlannedHours) {
      data.avgPlannedHours = data.avgPlannedHours - data.overPlannedHours;
    }
    return data;
  });
}

renderChart();

function renderChart() {

  var colors1 = ['#FFD692', '#A9EEFF'],
    avgPlannedHoursLineColor = "#36CFF5",
    plannedHoursLineColor = self.plannedHours > self.averagePlannedHours ? "#F5A623" : "#A8EEFF",
    color = d3.scaleOrdinal(colors1),
    margin = {
      top: 25,
      right: 180,
      bottom: 30,
      left: 40
    },
    svg = d3.select("#chart-container"),
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom;

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

  // var stackedData = d3.layout.stack()(self.normalisedData);
  var stack = d3.stack().keys(["avgPlannedHours", "overPlannedHours"]);
  var stackedData = stack(self.normalisedData);
  stackedData[1] = stackedData[1].map(function(stData, index) {
    stData[0] = 0;
    return stData;
  });

  var xAxis = d3.axisBottom();
  if (self.plannedHours > self.averagePlannedHours) {
    var swappedStack = stackedData[0];
    stackedData[0] = stackedData[1];
    stackedData[1] = swappedStack;
  }

  var yAxis = d3.axisLeft()

  var xScale = d3.scaleBand()
    .rangeRound([0, width])
    .padding(0.4)
    .align(0.3);

  xScale.domain(["foo", "bar", "baz"].concat(stackedData[0].map(function(d) {
    return d.data.day;
  })));

  var x1Scale = d3.scaleBand()
    .rangeRound([0, width])
    .padding(0.6);

  x1Scale.domain(["foo", "bar", "baz"].concat(stackedData[0].map(function(d) {
    return d.data.day;
  })));

  xAxis.scale(xScale)
    .tickValues(stackedData[0].map(function(d) {
      return d.data.day;
    }));

  var yScale = d3.scaleLinear()
    .rangeRound([height, 0]);
  if (self.plannedHours > self.averagePlannedHours) {
    yScale.domain([0,
      d3.max(stackedData[0],
        function(d) {
          return d[0] + d[1];
        })
    ]).nice();
  } else {
    yScale.domain([0,
      d3.max(stackedData[stackedData.length - 1],
        function(d) {
          return d[0] + d[1];
        })
    ]).nice();
  }

  yAxis.scale(yScale)
    .ticks(10);


  var layer = g.selectAll(".stack")
    .data(stackedData)
    .enter().append("g")
    .attr("class", "stack")
    .style("fill", function(d, i) {
      return color(i);
    });

  layer.selectAll("rect")
    .data(function(d) {
      return d;
    })
    .enter().append("rect")
    .attr("x", function(d) {
      return xScale(d.data.day);
    })
    .attr("y", function(d) {
      return yScale(d[1] + d[0]);
    })
    .attr("height", function(d) {
      return yScale(d[0]) - yScale(d[1] + d[0]);
    })
    .attr("width", 24);

  var workDoneLayer = g.selectAll(".work-done")
    .data(self.dataCopy)
    .enter().append("rect")
    .attr("class", "work-done")
    .attr("x", function(d) {
      return x1Scale(d.day);
    })
    .attr("y", function(d) {
      return yScale(d.doneWork);
    })
    .attr("width", 24)
    .attr("height", function(d) {
      return height - yScale(d.doneWork);
    });

  g.append("g")
    .attr("class", "x-axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);

  g.append("g")
    .attr("class", "y-axis")
    .call(yAxis);

  var averagLineData = self.dataCopy[0].avgPlannedHours;
  var plannedHoursDotted = d3.max(self.dataCopy, function(d) {
    return d.overPlannedHours;
  });
  g.append("svg:line")
    .attr("x1", 0)
    .attr("x2", width)
    .attr("y1", yScale(averagLineData))
    .attr("y2", yScale(averagLineData))
    .attr("stroke-dasharray", ("5, 5"))
    .style("stroke", avgPlannedHoursLineColor);
  g.append("svg:line")
    .attr("x1", 0)
    .attr("x2", width)
    .attr("y1", yScale(plannedHoursDotted))
    .attr("y2", yScale(plannedHoursDotted))
    .attr("stroke-dasharray", ("5, 5"))
    .style("stroke", plannedHoursLineColor);
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg id="chart-container" width="750" height="251"> </svg>

【讨论】:

  • 非常感谢您的帮助,很高兴拥有这种 hacky 方式。我还有一个疑问。如果你看看我的小提琴,我试图将堆积图和条形图分组,但我做不到。如果可以的话,我们如何对它们进行分组,以便图表正确放大以获取更多域值。这是该问题的链接stackoverflow.com/questions/44977119/…
【解决方案2】:

将您的 svg 视为 HTML 元素。你在里面,bar 被一个“d”元素分组。您只需添加 transform: translateX(50px) 即可将整个栏向右移动。

例如,只需在您的文档中添加这条 css 规则,以对齐黑色、蓝色、黄色条:

g.stack {
    transform: translateX(48px);
}

【讨论】:

  • 我尝试过这样做,但意识到这种方法是不对的,因为在 g 标签中绘制的 svg 内的条形图与 x 轴 g 标签是同级的。因此,如果我移动条形的 g 标签,则刻度线将无法正确显示,并且会因 x 轴上的大量域值而中断。
猜你喜欢
  • 1970-01-01
  • 2020-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-16
  • 2022-01-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多