【问题标题】:D3 bar chart where axis labels are hyperlinks from dataD3 条形图,其中轴标签是数据的超链接
【发布时间】:2021-01-23 23:19:00
【问题描述】:

我试图让水平条形图上的 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


    【解决方案1】:

    你快到了!

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

                // 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 属性,因为每个刻度的数据只包含数据的 topic 字符串。

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

    • 一方面,topic 字符串是我们希望轴显示为标签的内容。
    • 另一方面,我们希望引用 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>

    【讨论】:

    • 非常感谢@ee2Dev。使用您的示例,我成功了!
    • 根据您想要实现的目标,您可以将此方法与@rodrigo-divino 通过为所有刻度操作 DOM 提出的方法相结合
    【解决方案2】:

    SVG has an anchor tag &lt;a&gt; 启用超链接。它有两个重要的属性:

    • href:超链接
    • target:显示 URL 的位置(在本例中,我们将使用 _blank 作为新标签)

    现在问题变成了:如何用&lt;a&gt; 标签包裹轴的刻度?

    d3.axis{Direction} 方法在g.tick 元素内创建刻度,所以我们必须选择那些g.tick,在它们的父元素中插入一个&lt;a&gt; 元素,然后做一些移动操作来移动@ 987654328@里面新增了&lt;a&gt;

    这是一个将谷歌搜索链接到刻度的示例:

      const g = svg.append('g').call(d3.axisBottom(scale))
    
      g.selectAll('g.tick').each(function(tick) {
         d3.select(this.parentNode)
           .insert("a")
           .attr('href', 'https://www.google.com/search?q='+tick)
           .attr('target','_blank') // This makes the link open in a new window
           .append(() => this);
      })
    

    这里是an observable notebook to demonstrate it

    【讨论】:

    • 非常感谢@Rodrigo!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多