javascript - 如何限制D3条形图中的最大宽度

标签 javascript d3.js

我是 d3 条形图新手,下面是我想在项目中使用的条形图代码。

我只是想知道如何限制条形的最大宽度,因为当我只有一条记录时,条形的宽度变得非常大,实际上该条形占据了整个宽度,然后图形看起来不太好。 d3 中是否有任何方法可以限制每个条形的最大宽度。

<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
body { font: 12px Arial;}
path {
    stroke: steelblue;
    stroke-width: 2;
    fill: none;
}
.axis path,
.axis line {
    fill: none;
    stroke: grey;
    stroke-width: 1;
    shape-rendering: crispEdges;
}
.legend {
    font-size: 16px;
    font-weight: bold;
    text-anchor: middle;
}
</style>
<body>
<div id="d3id" ></div>
<!-- load the d3.js library -->
<script src="https://d3js.org/d3.v4.min.js"></script>

<script>
    var models = [
        {
            "model_name":"http://www.test.com",
            "field1":19,
            "field2":83
        },
        {
            "model_name":"http://www.test2.com",
            "field1":67,
            "field2":93
        },
        {
            "model_name":"http://www.test3.com",
            "field1":10,
            "field2":56
        },
        {
            "model_name":"http://www.test4.com",
            "field1":98,
            "field2":43
        },

        {
            "model_name":"http://www.test.com",
            "field1":19,
            "field2":83
        },
        {
            "model_name":"f7",
            "field1":67,
            "field2":93
        },
        {
            "model_name":"f8",
            "field1":10,
            "field2":56
        },
        {
            "model_name":"f9",
            "field1":98,
            "field2":43
        }
    ];
    models = models.map(i => {
        i.model_name = i.model_name;
        return i;
    });

    var container = d3.select('#d3id'),
        width = 500,
        height = 300,
        margin = {top: 30, right: 20, bottom: 30, left: 50},
        barPadding = .3,
        axisTicks = {qty: 5, outerSize: 0, dateFormat: '%m-%d'};

    var svg = container
        .append("svg")
        .attr("width", width)
        .attr("height", height)
        .append("g")
        .attr("transform", `translate(${margin.left},${margin.top})`);

    var xScale0 = d3.scaleBand().range([0, width - margin.left - margin.right]).padding(barPadding);
    var xScale1 = d3.scaleBand();
    var yScale = d3.scaleLinear().range([height - margin.top - margin.bottom, 0]);

    var xAxis = d3.axisBottom(xScale0).tickSizeOuter(axisTicks.outerSize);
    var yAxis = d3.axisLeft(yScale).ticks(axisTicks.qty).tickSizeOuter(axisTicks.outerSize);

    xScale0.domain(models.map(d => d.model_name));
    xScale1.domain(['field1', 'field2']).range([0, xScale0.bandwidth()]);
    yScale.domain([0, d3.max(models, d => d.field1 > d.field2 ? d.field1 : d.field2)]);

    var model_name = svg.selectAll(".model_name")
        .data(models)
        .enter().append("g")
        .attr("class", "model_name")
        .attr("transform", d => `translate(${xScale0(d.model_name)},0)`);

    /* Add field1 bars */
    model_name.selectAll(".bar.field1")
        .data(d => [d])
        .enter()
        .append("rect")
        .attr("class", "bar field1")
        .style("fill","#4267b2")
        .attr("x", d => xScale1('field1'))
        .attr("y", d => yScale(d.field1))
        .attr("width", xScale1.bandwidth())
        .attr("height", d => {
            return height - margin.top - margin.bottom - yScale(d.field1)
        });

    /* Add field2 bars */
    model_name.selectAll(".bar.field2")
        .data(d => [d])
        .enter()
        .append("rect")
        .attr("class", "bar field2")
        .style("fill","#69b3a2")
        .attr("x", d => xScale1('field2'))
        .attr("y", d => yScale(d.field2))
        .attr("width", xScale1.bandwidth())
        .attr("height", d => {
            return height - margin.top - margin.bottom - yScale(d.field2)
        });

    // Add the X Axis
    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", `translate(0,${height - margin.top - margin.bottom})`)
        .call(xAxis);

    // Add the Y Axis
    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis);

</script>
</body>

另外,如何调整标签以使其正确贴合?请帮助我。

最佳答案

您可以通过在附加矩形时操作宽度属性来轻松实现这一点。

这里我检查矩形的宽度是否大于宽度/10 (500/10),然后保持恒定值 50,否则使用默认值。您可以使用任何逻辑来操纵它。

.attr("width", function(d) {
  return xScale1.bandwidth() > width/10 ? width/10 : xScale1.bandwidth();
})

请在下面找到工作片段:

<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
body { font: 12px Arial;}
path {
    stroke: steelblue;
    stroke-width: 2;
    fill: none;
}
.axis path,
.axis line {
    fill: none;
    stroke: grey;
    stroke-width: 1;
    shape-rendering: crispEdges;
}
.legend {
    font-size: 16px;
    font-weight: bold;
    text-anchor: middle;
}
</style>
<body>
<div id="d3id" ></div>
<!-- load the d3.js library -->
<script src="https://d3js.org/d3.v4.min.js"></script>

<script>
    var models = [
        {
            "model_name":"http://www.test.com",
            "field1":19,
            "field2":83
        },
/*         {
            "model_name":"http://www.test2.com",
            "field1":67,
            "field2":93
        },
        {
            "model_name":"http://www.test3.com",
            "field1":10,
            "field2":56
        },
        {
            "model_name":"http://www.test4.com",
            "field1":98,
            "field2":43
        },
        
        {
            "model_name":"http://www.test.com",
            "field1":19,
            "field2":83
        },
        {
            "model_name":"f7",
            "field1":67,
            "field2":93
        },
        {
            "model_name":"f8",
            "field1":10,
            "field2":56
        },
        {
            "model_name":"f9",
            "field1":98,
            "field2":43
        } */
    ];
    models = models.map(i => {
        i.model_name = i.model_name;
        return i;
    });

    var container = d3.select('#d3id'),
        width = 500,
        height = 300,
        margin = {top: 30, right: 20, bottom: 30, left: 50},
        barPadding = .3,
        axisTicks = {qty: 5, outerSize: 0, dateFormat: '%m-%d'};

    var svg = container
        .append("svg")
        .attr("width", width)
        .attr("height", height)
        .append("g")
        .attr("transform", `translate(${margin.left},${margin.top})`);

    var xScale0 = d3.scaleBand().range([0, width - margin.left - margin.right]).padding(barPadding);
    var xScale1 = d3.scaleBand();
    var yScale = d3.scaleLinear().range([height - margin.top - margin.bottom, 0]);

    var xAxis = d3.axisBottom(xScale0).tickSizeOuter(axisTicks.outerSize);
    var yAxis = d3.axisLeft(yScale).ticks(axisTicks.qty).tickSizeOuter(axisTicks.outerSize);

    xScale0.domain(models.map(d => d.model_name));
    xScale1.domain(['field1', 'field2']).range([0, xScale0.bandwidth()]);
    yScale.domain([0, d3.max(models, d => d.field1 > d.field2 ? d.field1 : d.field2)]);

    var model_name = svg.selectAll(".model_name")
        .data(models)
        .enter().append("g")
        .attr("class", "model_name")
        .attr("transform", d => `translate(${xScale0(d.model_name)},0)`);

    /* Add field1 bars */
    model_name.selectAll(".bar.field1")
        .data(d => [d])
        .enter()
        .append("rect")
        .attr("class", "bar field1")
        .style("fill","#4267b2")
        .attr("x", d => xScale1('field1'))
        .attr("y", d => yScale(d.field1))
        .attr("width", xScale1.bandwidth())
        .attr("height", d => {
            return height - margin.top - margin.bottom - yScale(d.field1)
        });

    /* Add field2 bars */
    model_name.selectAll(".bar.field2")
        .data(d => [d])
        .enter()
        .append("rect")
        .attr("class", "bar field2")
        .style("fill","#69b3a2")
        .attr("x", d => xScale1('field2'))
        .attr("y", d => yScale(d.field2))
        .attr("width", function(d) {
          return xScale1.bandwidth() > width/2 ? width/4 : xScale1.bandwidth();
        })
        .attr("height", d => {
            return height - margin.top - margin.bottom - yScale(d.field2)
        });

    // Add the X Axis
    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", `translate(0,${height - margin.top - margin.bottom})`)
        .call(xAxis);

    // Add the Y Axis
    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis);

</script>
</body>

关于javascript - 如何限制D3条形图中的最大宽度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60893810/

相关文章:

javascript - AngularJS 如何区分以下 Action ?

javascript - 动态对象键

javascript - 对 MM :SS transition 使用 d3.interpolateString

svg - 我如何使用 SVG translate 将 d3.js 投影居中到给定的纬度和经度值?

javascript - d3.js 分层边缘捆绑 : embed json data in variable

javascript - 当子元素为空时隐藏 DOM 中的父元素

javascript - 如何防止BabelJS创建 'arguments'关键字的全局变量?

javascript - 我应该在 .gitignore 文件中写入 jsconfig.json 还是 tsconfig.json ?

javascript - 在散点上添加工具提示,为 D3.js 版本 4 生成错误

javascript - D3饼图未更新