【问题标题】:Fix the x-axis of D3 JS and add dotted lines to the y-axis and x-axis固定D3 JS的x轴,在y轴和x轴上添加虚线
【发布时间】:2021-02-05 13:42:12
【问题描述】:

对如何在 D3 JS 中执行以下实现有任何帮助吗?

  1. 修复不应滚动的 x 轴位置
  2. 在 x 轴上的值类似于 -2.5、-2.0、-1.5、-1.0、0、1.0、1.5、2.0、2.5 预期为:-2.5%、2.0%、-1.5%、-1.0%、0 %、1.0%、1.5%、2.0%、2.5%
  3. 如何在 y 轴上添加虚线?

代码笔: https://codepen.io/nchetankumar/pen/PozGmdy

const data = [{
  name: 'Good',
  value: 1
}, {
  name: 'Very Good',
  value: 2
}, {
  name: 'Very',
  value: 1
}, {
  name: 'Good1',
  value: 1
}, {
  name: 'Very Good1',
  value: 2
}, {
  name: 'Very1',
  value: 1
}, {
  name: 'Good2',
  value: 1
}, {
  name: 'Very Good2',
  value: 2
}, {
  name: 'Very2',
  value: 1
}, {
  name: 'Good3',
  value: 1
}, {
  name: 'Very Good3',
  value: 2
}, {
  name: 'Very3',
  value: 1
}, {
  name: 'Good4',
  value: 1
}, {
  name: 'Very Good5',
  value: 2
}, {
  name: 'Very5',
  value: 1
}, {
  name: 'Good6',
  value: 1
}, {
  name: 'Very Good6',
  value: 2
}, {
  name: 'Very6',
  value: 1
}, {
  name: 'Good7',
  value: 1
}, {
  name: 'Very Good7',
  value: 2
}, {
  name: 'Very7',
  value: 1
}, {
  name: 'Good8',
  value: 1
}, {
  name: 'Very Good8',
  value: 2
}, {
  name: 'Very9',
  value: 1
}];
// We want to center each rect around the value it's supposed to have.
// That means that we need to have a node width
let nodeWidth = 33;
let nodeHeight = 18;
if (this.viewBy !== 'Overlapping ' + this.jobOrSkill) {
  nodeWidth = 60;
  nodeHeight = 18;
}
let height = 1000;
const width = 620,
  paddingLeft = 0,
  paddingTop = 0,
  margin = {
    top: 20,
    left: 140,
    right: 40,
    bottom: 40
  };
if (this.totalSkills && this.totalSkills.length < 10) {
  height = 250;
}
if (this.totalSkills && this.totalSkills.length > 10 && this.totalSkills.length < 20) {
  height = 400;
}
if (this.totalSkills && this.totalSkills.length > 20 && this.totalSkills.length < 30) {
  height = 600;
}
const innerWidth = width + (margin.left + margin.right);
const innerHeight = height + (margin.top + margin.bottom);
// We also need to make sure there is space for all nodes, even at the edges.
// One way to get this is by just extending the domain a little.
const domain = d3.extent(data.map(d => Math.round(d.value)));
const x = d3.scaleLinear()
  .domain([Math.round(domain[0]) - 1, Math.round(domain[1]) + 1])
  .range([0, width]);

const y = d3.scaleBand()
  .domain(data.map((d, i) => d.name && d.name.length > 20 ? d.name = d.name.slice(0, 20) + '...' : d.name = d.name))
  .range([height, 0])
  .padding(1);

const svg = d3.select('#comparisionChartData')
  .attr('width', width + margin.left)
  .attr('height', height + margin.top + margin.bottom);

const g = svg
  .append('g')
  .attr('transform', `translate(${margin.left} ${margin.right})`);

g.append('g')
  .classed('x-axis', true)
  .attr('transform', `translate(0, ${height})`)
  .call(d3.axisBottom(x));

g.append('g')
  .classed('y-axis', true)
  .call(d3.axisLeft(y).tickPadding(10))
  .selectAll("text")
  .attr("transform", "translate(-60, 0)")
  .attr("text-anchor", "start")
  .append("title")
  .text(function(d) {
    return d;
  });

const bars = g.append('g')
  .selectAll('rect')
  .data(data)
  .attr('stroke', '#e5e5e5')
  .attr('class', 'line');

bars.exit().remove();

// All the same until here
bars.enter()
  .append('rect')
  // width has become a constant
  .attr('width', nodeWidth)
  // Now, transform each node so it centers around the value it's supposed to have
  .attr('transform', `translate(${-nodeWidth / 2} -8)`)
  // .merge(bars)
  // `x` denotes the placement directly again
  .attr('x', d => x(Math.round(d.value)))
  .attr('y', d => y(d.name))
  .attr('height', nodeHeight)
  .attr('fill', d => Math.round(d.value) > 0 && this.viewBy === 'Overlapping ' + this.jobOrSkill ? '#648fff' :
    this.viewBy === 'Overlapping ' + this.jobOrSkill && Math.round(d.value) === 0 ? '#9a16ca' :
    this.viewBy === 'Overlapping ' + this.jobOrSkill && Math.round(d.value) < 0 ? '#dc267f' :
    this.viewBy === 'Unique to Organization' ? '#016970' : this.viewBy === 'Absent to Organization' ? '#757575' : '#648fff');

// Now one more thing, we want to add labels to each node.
// `<rect>` can't have children, we we add them to the plot seperately
// using the same `data` as for the bars
const labels = g.append('g')
  .selectAll('text')
  .data(data);

labels.exit().remove();

labels.enter()
  .append('text')
  .attr('fill', 'white')
  .attr('text-anchor', 'middle') // center-align the text
  // .merge(bars)
  // `x` denotes the placement directly
  .attr('x', d => x(Math.round(d.value)))
  // Add half a bar's height to target the center of each node
  .attr('y', d => y(d.name) + y.bandwidth() / 4)
  // Actually fill in the text this.viewBy === 'Overlapping ' + this.jobOrSkill ? '+' + Math.round(d.value) :
  .text(d => Math.round(d.value) > 0 && this.viewBy === 'Overlapping ' + this.jobOrSkill ? Math.round(d.value) :
    this.viewBy === 'Unique to Organization' ? 'Unique' : this.viewBy === 'Absent to Organization' ? 'Absent' : Math.round(d.value))
  .attr('title', d => y(d.name))
  .attr('transform', `translate(0, 0)`)
  .attr('dy', 5);

【问题讨论】:

    标签: javascript css typescript d3.js bar-chart


    【解决方案1】:

    1 - 我不太明白第一个问题,因为 xAxis 似乎 固定而不滚动。

    2 - x 轴值似乎都是正数。但是,如果您像这样调用 x 轴刻度,则可以使用 vales 获得所需的格式:

    .call(d3.axisBottom(x).tickFormat(function(d) { return d+"%" }));
    

    如果值为负数,这也会显示减号。

    我个人建议将 vales 映射到 1 的分数(2.5% 将是 0.025 )并且只是:

    .call(d3.axisBottom(x).tickFormat(d3.format(".0%"));
    

    3 - 对于网格线,您可以在此处查看示例代码:https://bl.ocks.org/d3noob/879316f32be861b6870c98a277076d1b 和 .attr('stroke-dasharray'='2');

    【讨论】:

    • 感谢您的帮助。关于第一点,高度是自动的,但是如果我们将高度限制为 500 像素并且内容是可滚动的,那么在这种情况下,x 轴也会滚动。如果图表在这种情况下可滚动,则 x 轴不应滚动。
    • 所以 x 轴应该保持在原位。您正在寻找的是一个可平移的图表,其中一个轴是可滚动的。这里有一个例子:observablehq.com/@nicholasblexrud/pannable-chart-w-dual-y-axis where const body = parent.append("div").style("overflow-x", "scroll").style("-webkit-overflow-scrolling", "touch");and body.node().scrollBy(overwidth, 0);`施展魔法。您只需要为 y 轴调整它,而不是 x。
    猜你喜欢
    • 2021-12-28
    • 2016-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-01
    • 2020-11-05
    • 2016-12-19
    • 1970-01-01
    相关资源
    最近更新 更多