d3 js y axis tick text click event not working
-
I am using d3 js library to render a chart in jsreport. I want to open a hyperlink on clicking the y axis text labels. But the click event is not working.
Please find below my template.<html> <head> <style> * { font-family: Lato, Gotham, "Helvetica Neue", Helvetica, Arial, "sans-serif"; } .header { font-weight: 300; font-size: 25.2 px; color: #586A87; } .attributeLabel { color: black; font-size: 14px; font-weight: 400; height: 41px } .emptySpace { margin-bottom: 20px; } .title { fill: #4cabca; font-size: 12px; font-weight: bold; } line { stroke: #636363; } .bar { fill: #4cabca; } .label { font-weight: bold; font-size: 12px; } .label.low { text-anchor: end; } .x-axis { color: #636363; font-size: 10; font-family: sans-serif; text-anchor: middle; } .y-axis { pointer-events: auto !important; } </style> </head> <body> <div class="emptySpace"></div> <div id="wrapper"> <svg></svg> </div> <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script> <script src="https://d3js.org/d3.v6.min.js" charset="utf-8"></script> <script> var dataForChart = getDatasetForIssuesPriority(); const MARGIN = { TOP: 25, RIGHT: 0, BOTTOM: 25, LEFT: 100 }; const ROW_HEIGHT = 40; const LABEL_HEIGHT = 6; const LABEL_PADDING = 3; const MIN_BAR_WIDTH = 10; const TICK_PADDING = 20; const truncate = (node, maxWidth) => { let text = node.textContent; let nodeWidth = node.getComputedTextLength(); while (nodeWidth > maxWidth) { text = text.substring(0, text.length - 1); d3.select(node).html(text + '…'); nodeWidth = node.getComputedTextLength(); } }; var mainGroup = d3.select("svg") .attr("width", "900") .attr("height", "550") .append("g") .attr("class", "main-group") .attr("transform", "translate(" + MARGIN.LEFT + "," + MARGIN.TOP + ")"); var xScale = d3.scaleLinear(); var xAxis = d3.axisTop(xScale); var xAxisGroup = mainGroup.append("g") .attr("class", "x-axis"); const innerWidth = "722"; const innerHeight = "480"; const min = _.minBy(dataForChart, 'low').low ; const max = _.maxBy(dataForChart, 'high').high; const scalePadding = (max - min) / 5; xScale.domain([min - scalePadding, max + scalePadding]) .range([0, innerWidth]); xAxis.scale(xScale); xAxisGroup.call(xAxis) .call(g => g.selectAll(".domain").remove()); var yScale = d3.scaleBand() .padding(0.5); var yAxis = d3.axisLeft(yScale) .tickPadding(TICK_PADDING); var yAxisGroup = mainGroup.append("g") .attr("class", "y-axis"); const yAxisWidth = MARGIN.LEFT-TICK_PADDING; yScale.domain(_.map(dataForChart, d => d.id)) .range([0, innerHeight]); yAxis.scale(yScale) .tickSize(-innerWidth); yAxisGroup.call(yAxis) .call(g => g.selectAll(".domain").remove()) .selectAll("line") .attr("class", "line") .attr("transform", "translate(0, "+ (yScale.bandwidth()/2) +")"); yAxisGroup.selectAll(".tick text") .attr("class", "title") .each((_, i, nodes) => truncate(nodes[i], yAxisWidth)); var plotGroup = mainGroup.append("g") .attr("class", "plot"); var barGroups = plotGroup.selectAll("g").data(dataForChart) .enter().append("g"); var bars = barGroups.append("rect") .attr("class", "bar"); var lowLabels = barGroups.append("text") .attr("class", "label low"); var highLabels = barGroups.append("text") .attr('class', 'label high'); barGroups.attr('transform', d => `translate(${xScale(d.low)}, ${yScale(d.id)})`); bars.attr('width', d => calculateBarWidth(d)) .attr('height', yScale.bandwidth()); lowLabels.attr('x', -LABEL_PADDING) .attr('y', (yScale.bandwidth()+LABEL_HEIGHT)/ 2) .text(d => d.low); highLabels.attr('x', d => calculateBarWidth(d) + LABEL_PADDING) .attr('y', (yScale.bandwidth()+LABEL_HEIGHT)/ 2) .text(d => d.high); yAxisGroup.selectAll(".tick text") .on("click", function(d) { document.location.href = d.redirectUri; }) ; function calculateBarWidth(d) { const barWidth = xScale(d.high) - xScale(d.low); if (barWidth < MIN_BAR_WIDTH) { return MIN_BAR_WIDTH; } return barWidth; } function getDatasetForIssuesPriority() { var dataset = []; for (var i = 0; i < 10; i++) { var arrayItem = { "id": 'Test' + i, "redirectUri": "www.google.com", "low": i, "high": i + 10 }; dataset.push(arrayItem) } return dataset } </script> </body> </html>
-
The javascript doesn't run inside pdf. It runs before in chrome which converts the final html/css into pdf.
Chrome can render<a>
anchors withhref
as links inside pdf.
This means you could be able to change the element you want to work as a link intoa
anchor withhref
and chrome then print it into pdf as a link.
-
How can I convert the axis labels to <a> tags?
-
I am not so much familiar with d3.js, but after quick googling I see you can add HTML to the chart like this:
mainGroup.append("text") .attr("x", 265 ) .attr("y", 240 ) .style("text-anchor", "middle") .html("<a href='https://jsreport.net'>my link</a>");
Chrom converts this to pdf as a clickable link.
Reference: https://stackoverflow.com/questions/24827589/d3-appending-html-to-nodes
-
Thanks Jan!! This worked.