D3: Hovering over the word in text the corresponding bar should be highlighted and make words in text clickable

D3: Hovering over the word in text the corresponding bar should be highlighted and make words in text clickable
0

#1

I am still a great beginner when it comes to D3 and JavaScript. I could implement my code in a way that I can upload a text file, transfer to the content to the next page, and render the bar charts. However I still do not have any clue how to realize the following function. Whenever the user hover over a word in the text the corresponding bar should be highlighted in a certain color. Also, how can I make the words in the text clickable. I hope you can help me out. I could not find anything appropriate on the internet to solve these problems.

Here is the page to upload the text file:

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <link href="https://unpkg.com/filepond/dist/filepond.css" rel="stylesheet">
    <script src="https://d3js.org/d3.v5.min.js"></script>
    <meta charset="UTF-8">
    <title>File Upload</title>

    <style>
        .filepond--root {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
            Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
            'Segoe UI Symbol';
        }
        .filepond--drop-label {
            color: #000033;
        }
        .filepond--panel-root {
            background-color: transparent;
            border: 1px solid #6666ff;
        }

        .filepond--panel-root {
            background-color: #e5e5ff;
        }

        .filepond--label-action {
            text-decoration-color: #a7a4a4;
        }

        /* the color of the focus ring */
        .filepond--file-action-button:hover,
        .filepond--file-action-button:focus {
            box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.9);
        }

        h2 {
            width: 100%;
            text-align: center;
            font-size: 17px;
            border-bottom: 1px solid #939393;
            line-height: 0.1em;
            margin: 10px 0 20px;
        }

        h2 span {
            background:#fff;
            padding:0 10px;
        }


    </style>

</head>
<body>

<input type="file" class="filepond" id="fileInput">


<h2><span>OR</span></h2>

<form>
    <div class="form-group">
        <label for="textArea1">Paste your text here</label>
        <textarea class="form-control" id="textArea1" rows="3"></textarea>
    </div>
</form>
<button type="button" class="btn btn-outline-primary" onclick ="myFunction()">Submit</button>


<script src="https://unpkg.com/filepond/dist/filepond.js"></script>
<script>
    FilePond.parse(document.body);

    document.getElementById("fileInput").addEventListener("change",getF);
        var res;

         function getF(event) {

             // check if textarea empty

                 var input = event.target;

                 readContentFile(input.files[0]).then(content => {
                     res = content;
                     getContent(res);
                 }).catch(error => console.log(error));


         }


    function readContentFile(file){


            var reader = new FileReader();

            return new Promise((resolve,reject) =>{
                reader.onload = event => resolve(event.target.result);
                reader.onerror = error => reject(error);
                reader.readAsText(file, 'ISO-8859-1');
            })
    }

    String.prototype.trim = function() {
        return this.replace(/^\s+|\s+$/g,"");
    };

   function getContent(file) {
           localStorage.setItem("fileContent", file);
       return file;
   }

    function myFunction(){
        if (!(document.getElementById("textArea1").value.trim() == '')) {
            localStorage.setItem("fileContent", document.getElementById("textArea1").value);
        }
             location.href="AnotherPage.html";
    }

    var bspText = ["Hello", "World"];

   var div= d3.select("body").append("div")
       .attr("width",960)
       .attr("height",500);
   div.append("p");


</script>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
</body>
</html>

Here is the page where the text and bar chart are rendered.

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <script src="https://d3js.org/d3.v5.min.js"></script>
    <meta charset="UTF-8">
    <title>AnotherPage</title>

    <style>
        .row {
            margin-top: 30px;
        }
        [class^='col'], [class*=' col'] {
            margin-top: 30px;
        }

        #blockText{
            border-left: 1.5px solid black;
        }

    </style>
</head>
<body>
<div class="container text-center">
    <div class="row">
        <div class="col-md-6" id="rectsBlock">
            <svg id="barchart"></svg>

        </div>
        <div class="col-md-6" id="blockText">
        </div>
    </div>
</div>
</body>
<script>
    var textContent, textDiv;
   textContent = document.createTextNode(localStorage.getItem("fileContent"));
    textDiv = document.getElementById("blockText");
    textDiv.appendChild(textContent);

    // extracting words

   // var engPattern = /\w+/g;
        var engPattern = /\b[^\d\W]+\b/g;

       //var krPattern = /[\uac00-\ud7af]|[\u1100-\u11ff]|[\u3130-\u318f]|[\ua960-\ua97f]|[\ud7b0-\ud7ff]/g;

        var res = localStorage.getItem("fileContent").match(engPattern);

       // console.log("Sprache"+localStorage.getItem("fileContent").match(krPattern))

        var unique = res.reduce(function (a, b) {
            if (a.indexOf(b) < 0)
                a.push(b);
            return a;
        }, []);

        function removeOneLetterElem(arr){
            var index = 0;
            for(var i = 0;i<arr.length;i++){
                if(arr[i].length ===1 && arr[i]!=="a"){
                    console.log("Wert ist "+arr[i]);
                    index = arr.indexOf(arr[i]);
                    console.log(index);
                    arr.splice(index,1);
                }
            }
        }
       removeOneLetterElem(unique);

        console.log(unique);

        //function distinguishLang(lang){
        //}

    console.log("Value is"+document.getElementsByClassName("bar").textContent);

    // percentages

    var arrNums = [];

    generatePercentages();
    function generatePercentages(){
        var arr = [];

        for(var i = 0;i<unique.length;i++){
            arr.push(Math.floor((Math.random()*100) + 1));
        }
        arrNums = arr;
    }


    // building json

    var jsonData;
    var wordset ={};

    function buildJson(){
        var words = [];
        var word, val, wordElem;

        wordset.words = words;
        for(var i=0;i<unique.length;i++){
        word = unique[i];
        val = arrNums[i];
        wordElem={
            "word":word,
            "value":val
        };

        wordset.words.push(wordElem);
        }
        jsonData = JSON.stringify(wordset);
    }

    buildJson();
        // bar chars
   console.log(wordset.words);


    var margin = {top: 5, right: 80, bottom: 30, left: 90},
        width = 600- margin.left - margin.right,
        height = 1500 - margin.top - margin.bottom;

    var svg = d3.select("#rectsBlock").select("#barchart")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom);

    var x = d3.scaleLinear().range([0,width]);
    var y = d3.scaleBand().range([height,0]);

    var g =  svg.append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    wordset.words.sort(function(a,b){
        return a.value-b.value;
    });
    x.domain([0, d3.max(wordset.words, function(d){
        return d.value;})]);
    y.domain(wordset.words.map(function(d){
       return d.word;
    })).padding(0.2);

    g.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")");

    g.append("g")
        .attr("class", "y axis")
        .call(d3.axisLeft(y).tickSize(0));


   var bars = g.selectAll(".bar")
        .data(wordset.words)
        .enter()
        .append("rect")
        .attr("class","bar")
        .attr("x",0)
        .attr("height",y.bandwidth())
        .attr("y", function(d) { return y(d.word); });

        bars.transition()
        .duration(50)
        .delay(function (d, i) {
            return i * 20;
        })
        .attr("width", function(d){
            return x(d.value);
        })
        .attr("fill","#1bf0c0");


        g.selectAll(".text")
        .data(wordset.words)
        .enter()
        .append("text")
        .transition()
        .duration(50)
        .delay(function (d, i) {
            return i * 20;
        })
        .attr("class","label")
         .attr("y",function(d){
            return y(d.word)+y.bandwidth()-1;
        })
        .attr("x",function(d){
            return x(d.value)+3;
        })
        .attr("dy",".12em")
        .style("font-size", "11px")
        .text(function(d){
            return d.value+"%";
    });

    bars.attr("id",function(d,i){
        return i;})
        .on("mouseover",function(d){
            console.log("Printing words "+d.word);
                d3.select(this)
                    .style("fill", "brown")

        }).on("mouseout",function(d,i){
            d3.select(this).style("fill","#1bf0c0");
        });


    d3.select("#blockText")
        .on("click", function(){
        alert("clicked");
    });

</script>


<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
</body>
</html>

And here are text files for testing : https://ufile.io/xz9wd

I wanted to remove the duplicates that’s why I have saved all the words in an array.

I hope you can help me out. Thank you very much.


#2

Can you build this on codepen please.


#3

The problem is solved, but when you hover a word that bar can be at the bottom part so I want to dynamically scroll to that part. Is there a possibility?


#4

Here is a fiddle: http://jsfiddle.net/j4qav07u/

But I have another problem. Because there are too many words in the bar chart, words do appear at the bottom of the screen. How is it possible to implement a dynamic scroll to that specific bar when the user hover over a word in the text, which bar is at the bottom of the screen. And on a mouseout it should be scrolled back to the top of the screen.

I hope you can help out.

Thank you very much.


#5

Something like this? https://codepen.io/JohnnyBizzel/pen/xqbjVQ