首页 > 解决方案 > d3:将鼠标悬停在文本中的单词上同时突出显示相应的条并使文本中的单词可点击

问题描述

亲爱的 Stackoverflow 社区

在 D3 和 JavaScript 方面,我仍然是一个很棒的初学者。我可以通过上传文本文件、将内容传输到下一页以及呈现条形图的方式来实现我的代码。但是我仍然不知道如何实现以下功能。每当用户将鼠标悬停在文本中的某个单词上时,相应的栏应该以某种颜色突出显示。另外,如何使文本中的单词可点击。我希望你能帮助我。我在互联网上找不到任何合适的东西来解决这些问题。

非常感谢。这是我的代码:加载文本文件:

   <!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";
        }

    </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>

带有图表和文本的页面:

<!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>

这些是用于测试的示例文本文件:

https://ufile.io/xz9wd

标签: javascripthtmlcssd3.js

解决方案


这是一种方法:

  1. 与其将整个文本作为内容附加到 中#blockText,不如创建span元素并将相应的单词存储为键,这样可以更轻松地向其中添加事件。

    res.forEach(function (word) {
        var span = document.createElement('span');
        span.textContent = word + ' ';
        span.setAttribute('data-key', word);
        textDiv.appendChild(span);
    });
    
  2. 添加事件:我正在使用 jQuery 将mouseover,mouseoutclick事件添加到上面添加span的 s 中。如果您不打算包含 jQuery,则始终可以将addEventListener分配给新创建的跨度。

    $('div#blockText span[data-key]').on('mouseover', function () {
        var key = $(this).data('key');
        d3.select("#rectsBlock").select("#barchart").select('svg rect[data-key='+key+']').style('fill', 'brown');
    }).on('mouseout', function () {
        var key = $(this).data('key');
        d3.select("#rectsBlock").select("#barchart").select('svg rect[data-key='+key+']').style('fill', '#1bf0c0');
    }).on('click', function () {
        console.log("Clicked word: " + $(this).data('key'));
    });
    

你的 JSFIDDLE 的分支:http: //jsfiddle.net/j4qav07u/

内联片段:

<!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://code.jquery.com/jquery-3.2.1.js"></script>
    <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;

		var fileContent = 'As ending of freedom of movement is central to the deal, some MPs have been calling for the government to publish the white paper for its post-Brexit immigration bill before next weekís meaningful vote.\n\nThe government has told those MPs this is not likely to happen. On Wednesday, the home secretary, Sajid Javid, said it was ìstill his intentionî to publish it this month ñ a choice of words opposition MPs met with groans and sighs.\n\nDefending the delay, Javid told MPs: ìItís worth keeping in mind that this is the biggest change in our immigration system in four decades. Itís important that we take the time and we get it right.î\n\nJavid also said freedom of movement would end, ìdeal or no dealî ñ in effect saying that while it was a key part of the deal, it was not strictly tied to what May was offering.\n\nHe also said MPs had been given glimpses of what the post-Brexit immigration system would look like.\n\nThe government is proposing a single immigration system that treats migrants from EU countries in the same way as those from non-EU countries. Highly skilled workers who want to live and work in Britain will be given priority.\n\nHowever, the government says the ability of people from abroad to deliver services and student exchange programmes will form part of future trade agreements.';


   textContent = document.createTextNode(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 = fileContent.match(engPattern);

				res.forEach(function (word) {
        	var span = document.createElement('span');
          span.textContent = word + ' ';
          span.setAttribute('data-key', word);
        	textDiv.appendChild(span);
        });
        
        $('div#blockText span[data-key]').on('mouseover', function () {
        	var key = $(this).data('key');
          d3.select("#rectsBlock").select("#barchart").select('svg rect[data-key='+key+']').style('fill', 'brown');
        }).on('mouseout', function () {
        	var key = $(this).data('key');
          d3.select("#rectsBlock").select("#barchart").select('svg rect[data-key='+key+']').style('fill', '#1bf0c0');
        }).on('click', function () {
        	console.log("Clicked word: " + $(this).data('key'));
        });
        
       // 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;}).attr('data-key', function (d) { return d.word; })
        .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>

希望这可以帮助。


推荐阅读