首页 > 解决方案 > D3 条形图,其中轴标签是数据的超链接

问题描述

我试图让水平条形图上的 y 轴链接成为基于数据值的超链接。而且我无法让它工作,而且我找不到它已经完成的例子。

任何示例或建议将不胜感激。

我的代码是:

function dohorizontalbarchartD3(data, elementid, topic, topicscore, width, height, margin)
{
        var y = d3.scaleBand().range([height, 0]).padding(0.1);
        var x = d3.scaleLinear().range([0, width]);
        var svg = d3.select(elementid).append("svg")
                .attr("width", width + margin.left + margin.right)
                .attr("height", height + margin.top + margin.bottom)
                .append("g")
                .attr("fill", "steelblue")
                .attr("transform",
                            "translate(" + margin.left + "," + margin.top + ")");

            // Scale the range of the data in the domains
            x.domain([0, d3.max(data, function(d){ return d[topicscore]; })])
            y.domain(data.map(function(d) { return d[topic]; }));

            // append the rectangles for the bar chart
            var bars = svg.selectAll(".bar")
                    .data(data)
                .enter().append("rect")
                    .attr("class", "bar")
                    .attr("width", function(d) {return x(d[topicscore]); } )
                    .attr("y", function(d) { return y(d[topic]); })
                    .attr("height", y.bandwidth())

            // add the x Axis
            svg.append("g")
                    .attr("transform", "translate(0," + height + ")")
                    .call(d3.axisBottom(x));

            // add the y Axis
            svg.append("g")
                    .call(d3.axisLeft(y))
                    .style("cursor", "pointer")
                    .on("click", function(d) {window.location.href = "signal.html?id=" + d["id"];}); 
}

var data = [{topic: "disaster management", weight: 5.044282881692003, "id": 10}, {topic: "analytics", weight: 5.111022997620935, "id": 11}, {topic: "systems management", weight: 5.255783212161269, "id": 12}, {topic: "human resources", weight: 5.420123698898777, "id": 13}, {topic: "machine learning", weight: 6.357388316151202, "id": 14}, {topic: "automation", weight: 6.579434311393074, "id": 15}, {topic: "health and safety", weight: 7.607482274852919, "id": 16}, {topic: "cost control", weight: 7.876784769962982, "id": 17}, {topic: "climate change", weight: 8.24345757335448, "id": 18}, {topic: "inventory management", weight: 8.511369645690111, "id": 19}, {topic: "transformation", weight: 8.650363516192993, "id": 20}, {topic: "supply chain", weight: 8.916204070843246, "id": 21}, {topic: "water treatment", weight: 9.996866186148543, "id": 22}];

var margin = {top: 10, right: 20, bottom: 30, left: 200};
dohorizontalbarchartD3(data, "#scoutblock1", "topic", "weight", 300, 500, margin);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<!DOCTYPE html>
<html lang="en">

<body>
<div id="scoutblock1"></div>
</body>
</html>

标签: d3.js

解决方案


你快到了!

让我们看看您尝试附加链接的代码行:

            // add the y Axis
        svg.append("g")
                .call(d3.axisLeft(y))
                .style("cursor", "pointer")
                .on("click", function(d) {window.location.href = "signal.html?id=" + d["id"];}); 

使用selection.call(d3.axisLeft(y))d3 添加一个轴,该轴首先是轴线的一个path元素,也就是每个标签的刻度线,在各自的位置有一条微小的正交线。像很多时候一样,元素检查器是您的朋友,我鼓励您在浏览器中打开它并查看 DOM 中生成的元素。

在此处输入图像描述

这一切都按预期工作,但是,您当前所指的选择没有附加任何数据。同样,让我们​​使用检查器查看属性,您看不到任何__data__属性:

在此处输入图像描述

这意味着,您在.on("click", function(d)...)回调函数中对数据的引用将始终undefined具有d.

d3 所做的是它创建了记号作为子节点,并且数据分别附加到每个记号。因此,您必须做的一件事是.on("click", function(d)...)为每个刻度调用。

这是一种方法:

// add the y Axis
        svg.append("g")
            .attr("class", "y axis") // assign a class, so we can reference it below
            .call(d3.axisLeft(y));

        svg.select(".y.axis") // select the g element with the y axis
           .selectAll(".tick") // select all ticks of the axis and do for each:
              .style("cursor", "pointer")
              .on("click", function(d) { 
                 // your callback 
               });

现在我们有了逻辑,我们要调用超链接。附加到每个刻度的数据基于我们提供给的数据d3.axisLeft(),即y。鉴于我们选择的y函数,每个刻度都包含每个数据元素的主题字符串。让我们再用元素检查器来确认一下:

在此处输入图像描述

这意味着到目前为止,我们无法访问回调函数中的 id 属性,因为每个刻度的数据只包含数据的主题字符串。

我们注意到有两个单独的要求:

  • 一方面,主题字符串是我们希望轴显示为标签的内容。
  • 另一方面,我们想引用id属性来调用超链接。

有很多方法可以做到,为了在回调函数中保留后一个要求,我们可以这样做:

            svg.select(".y.axis")
               .selectAll(".tick")
                 .style("cursor", "pointer")
                 .on("click", function(d) {
                    var id = data.find(function(ele) { return ele.topic === d;}).id;
                    window.location.href = "signal.html?id=" + id;
                 });

回想一下,d每个刻度元素中的数据仅引用相应的主题字符串。所以我们可以遍历原始数据来找到第一个包含主题的对象d。对于那个对象,我们想要拥有 id 属性。

这是完整的代码(我稍微更改了您的 html 代码以符合惯例):

        var data = [{topic: "disaster management", weight: 5.044282881692003, "id": 10}, {topic: "analytics", weight: 5.111022997620935, "id": 11}, {topic: "systems management", weight: 5.255783212161269, "id": 12}, {topic: "human resources", weight: 5.420123698898777, "id": 13}, {topic: "machine learning", weight: 6.357388316151202, "id": 14}, {topic: "automation", weight: 6.579434311393074, "id": 15}, {topic: "health and safety", weight: 7.607482274852919, "id": 16}, {topic: "cost control", weight: 7.876784769962982, "id": 17}, {topic: "climate change", weight: 8.24345757335448, "id": 18}, {topic: "inventory management", weight: 8.511369645690111, "id": 19}, {topic: "transformation", weight: 8.650363516192993, "id": 20}, {topic: "supply chain", weight: 8.916204070843246, "id": 21}, {topic: "water treatment", weight: 9.996866186148543, "id": 22}];

        var margin = {top: 10, right: 20, bottom: 30, left: 200};
        dohorizontalbarchartD3(data, "#scoutblock1", "topic", "weight", 300, 500, margin);

        function dohorizontalbarchartD3(data, elementid, topic, topicscore, width, height, margin) {
            var y = d3.scaleBand().range([height, 0]).padding(0.1);
            var x = d3.scaleLinear().range([0, width]);
            var svg = d3.select(elementid).append("svg")
                    .attr("width", width + margin.left + margin.right)
                    .attr("height", height + margin.top + margin.bottom)
                    .append("g")
                    .attr("fill", "steelblue")
                    .attr("transform",
                                "translate(" + margin.left + "," + margin.top + ")");

            // Scale the range of the data in the domains
            x.domain([0, d3.max(data, function(d){ return d[topicscore]; })])
            y.domain(data.map(function(d) { return d[topic]; }));

            // append the rectangles for the bar chart
            var bars = svg.selectAll(".bar")
                    .data(data)
                .enter().append("rect")
                    .attr("class", "bar")
                    .attr("width", function(d) {return x(d[topicscore]); } )
                    .attr("y", function(d) { return y(d[topic]); })
                    .attr("height", y.bandwidth())

            // add the x Axis
            svg.append("g")
                .attr("transform", "translate(0," + height + ")")
                .call(d3.axisBottom(x));

            // add the y Axis
            svg.append("g")
                .attr("class", "y axis")
                .call(d3.axisLeft(y));

            svg.select(".y.axis")
               .selectAll(".tick")
                 .style("cursor", "pointer")
                 .on("click", function(d) {
                    var id = data.find(function(ele) { return ele.topic === d;}).id;
                    window.location.href = "signal.html?id=" + id;
                  });
        }
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>title</title>
    <!--link rel="stylesheet" href="style.css"-->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
  </head>
  <body>
    <div id="scoutblock1"></div>


推荐阅读