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 + '&hellip;');
                        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 with href as links inside pdf.
    This means you could be able to change the element you want to work as a link into a anchor with href 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.


Log in to reply
 

Looks like your connection to jsreport forum was lost, please wait while we try to reconnect.