You are almost there!
Let's look at the code lines where you try to attach the links:
// 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"];});
With selection.call(d3.axisLeft(y))
d3 is adding an axis which is first of all a path
element for the axis line and so called ticks for each label with a tiny orthogonal line at the respective position. Like many times, the element inspector is your friend, I encourage you to open it up in your browser and look at the resulting elements in your DOM.
That's all working as expected, however, the very selection you are currently refering to, has no data attached to it. Again, let's look with the inspector into the properties and you see no __data__
property:
That means, your reference to data, in the .on("click", function(d)...)
callback function will always have undefined
as the value of d
.
What d3 does is it has created ticks as the children nodes and there data is attached to each tick, respectively. So one thing you have to do is call the .on("click", function(d)...)
for each tick.
Here is one way to do it:
// 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
});
Now we have the logic in place, we want to call the hyperlink. The data which is attached to each tick is based on what we provided to the d3.axisLeft()
and that is y
. Given our choice of they
function, each tick contains the topic string of each data element. Let's look again with the element inspector to confirm:
That means as of now, we cannot access the id property in your callback function because the data of each tick just contains the topic string of the data.
We notice to have 2 separate requirements:
- On the one hand, the topic string is what we want the axis to display as a label.
- on the other hand we want to reference the id property to call the hyperlink.
There are many ways to do it, to keep the latter requirement in the callback function, we can do:
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;
});
So recall, that data d
in each tick element refer solely to the corresponding topic string. So we can loop through the original data to find the first object which contains the topic d
. Of that object, we want to have the id property.
Here is the complete code (I changed your html code a bit to match common practice):
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>