使用 HTML 输入在 D3 中进行动态过滤

Posted

技术标签:

【中文标题】使用 HTML 输入在 D3 中进行动态过滤【英文标题】:Dynamic filtering in D3 with HTML input 【发布时间】:2015-05-09 10:37:42 【问题描述】:

我远不是一个 D3 极客,只是从制表符分隔的文件中读取了我的第一个“散点图”之一。每个点(或圆圈)都有一个日期(x 轴)和一个计数(y 轴)和一个句子,鼠标悬停时显示。包含数据的代码和标签文件在这里:

https://gist.github.com/sytpp/3a070a6ed6834169a85b

我添加了一个文本框,我可以在其中输入搜索词(第 39-42 行),当我点击“告诉我”时,我希望它突出显示与第 2 列(谁)中的搜索词匹配的所有点和/或 3 个(什么)数据。我设法在搜索时更改了所有点(包括图例)的不透明度(第 193-201 行),但没有弄清楚如何根据文本匹配动态选择子部分。

function handleClick(event)
    console.log(document.getElementById("myVal").value)
    draw(document.getElementById("myVal").value)
return false;


function draw(val)
    d3.select("body").selectAll("circle").style("opacity", .3);

我在流动数据上找到了类似的示例,但无法重现。非常感谢您的帮助!

【问题讨论】:

如果您将数据绑定到每个圆圈,则典型模式是 d3.select("body").selectAll("circle").style("opacity", function(d) .. .//这里是你的逻辑,你根据它返回一定的不透明度......;) 所以我在数据 d 可用的函数中添加了 handleClick 和 draw 函数,但是当我点击搜索时出现此错误:referenceError:handleClick 未定义。 是的,handleClick 的函数调用保持全局范围,因为它是从表单调用的。请参阅下面的答案 - 希望对您有所帮助! 【参考方案1】:

你的可视化真的很酷!我看了你的代码,你只需要做一些小改动:

首先,您当前的函数 draw() 包含错误的选择。

d3.select("body").selectAll("circle").style("opacity", .3);

它不仅包含图中的圆圈,还包含图例中的圆圈!。因此,当您在图中绘制圆圈时,请为它们分配适当的类名:

svg.selectAll("circle.dot")                                    
    .data(data)                                            
    .enter()...

所以在函数draw中,您可以通过以下方式获得正确的选择:

d3.select("body").selectAll("circle.dot")

要为匹配搜索的圆圈设置不透明度,您只需在回调函数中编写逻辑即可。我分离了回调(并将搜索词存储在全局变量中)......

var valOpacity = function(d)  
      if ((d.what.search(currentSearchTerm) != -1) || (d.who.search(currentSearchTerm) != -1)) 
        return 1;
      
      else 
        return 0.1;
      
    ;

因为我们可以首先将其重用于选择...

function draw()
    d3.select("body").selectAll("circle.dot").style("opacity", valOpacity);

...第二个是调整你的 mouseout 事件以正确设置不透明度:

.on("mouseout", function()
        d3.select(this).transition().duration(50).attr("r", 5).style("opacity", valOpacity); 
    );

这是完整的工作代码:

<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */

body  font: 16px Arial;

path  
    stroke: steelblue;
    stroke-width: 2;
    fill: none;


.axis path,
.axis line 
    fill: none;
    stroke: grey;
    stroke-width: 1;
    shape-rendering: crispEdges;


div.tooltip 
    position: absolute;    
    text-align: left; 
    width: 300px;    
    height: 150px;        
    padding: 2px;    
    font: 16px Arial;   
    background: none;    
    border: 0px;                    
    border-radius: 2px;




</style>
<body>

<form name="myform" onSubmit="return handleClick()">
        <input type="text" id="myVal" placeholder="Search WHO should do WHAT">
        <input name="Submit"  type="submit" value="Tell me!" >
</form>  

<!-- load the d3.js library -->    
<script type=
    "text/javascript" src="http://d3js.org/d3.v3.min.js">
</script>

<script>

// Set the dimensions of the canvas / graph
var margin = top: 30, right: 20, bottom: 30, left: 60,
    width = 800 - margin.left - margin.right,
    height = 600 - margin.top - margin.bottom;

// Parse the date / time
var parseDate = d3.time.format("%Y-%m-%d").parse;
var formatTime = d3.time.format("%d %B %Y");// Format tooltip date / time

var currentSearchTerm = "";

// Set the rangestrann
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);

var flags = ["LEADERS","LETTERS,BRIEFINGS,ETC...","INTERNATIONAL","ASIA (incl. CHINA)","AMERICAS", "EUROPE (incl. BRITAIN)","BUSINESS"]
var cols = ["#b2182b","#969696","#252525","#08519c","#fec503","#5aae61","#de77ae" ]

var color = d3.scale.ordinal().domain(flags).range(cols);

// Define the axes
var xAxis = d3.svg.axis().scale(x)
    .orient("bottom").ticks(5);

var yAxis = d3.svg.axis().scale(y)
    .orient("left").ticks(5);


// Define 'div' for tooltips
var div = d3.select("body")
    .append("div")  // declare the tooltip div 
    .attr("class", "tooltip")
    .style("opacity", 0);

// Adds the svg canvas
var svg = d3.select("body")
    .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
    .append("g")
        .attr("transform", 
              "translate(" + margin.left + "," + margin.top + ")");


// Legend              
var legend = d3.select("body").append("svg")
                    .attr("width",200)
                    .attr("height",200)
                    .append("g")
                        .attr("transform","translate(10,14)");


legend.append("circle").attr("cx", 10).attr("cy", 10).style("fill", cols[0]).attr("r", 20).style("opacity", .7);
    legend.append("text").attr("x", 40).attr("y",16).style("font-size","15px").text("Click to read article.");

legend.append("circle").attr("cx", 10).attr("cy", 55).style("fill", cols[6]).attr("r", 5);
    legend.append("text").attr("x", 25).attr("y",60).style("font-size","12px").text(flags[6]);

legend.append("circle").attr("cx", 10).attr("cy", 70).style("fill", cols[5]).attr("r", 5);
    legend.append("text").attr("x", 25).attr("y",75).style("font-size","12px").text(flags[5]);

legend.append("circle").attr("cx", 10).attr("cy", 85).style("fill", cols[4]).attr("r", 5);
    legend.append("text").attr("x", 25).attr("y",90).style("font-size","12px").text(flags[4]);

legend.append("circle").attr("cx", 10).attr("cy", 100).style("fill", cols[3]).attr("r", 5);
    legend.append("text").attr("x", 25).attr("y",105).style("font-size","12px").text(flags[3]);

legend.append("circle").attr("cx", 10).attr("cy", 115).style("fill", cols[2]).attr("r", 5);
    legend.append("text").attr("x", 25).attr("y",120).style("font-size","12px").text(flags[2]);

legend.append("circle").attr("cx", 10).attr("cy", 130).style("fill", cols[1]).attr("r", 5);
    legend.append("text").attr("x", 25).attr("y",135).style("font-size","12px").text(flags[1]);

legend.append("circle").attr("cx", 10).attr("cy", 145).style("fill", cols[0]).attr("r", 5);
    legend.append("text").attr("x", 25).attr("y",150).style("font-size","12px").text(flags[0]);


// Get the data
d3.tsv("EcoSHOULDS.tab", function(error, data) 

    data.forEach(function(d) 
        d.date = parseDate(d.date);
    );

    // Scale the range of the data
    x.domain(d3.extent(data, function(d)  return d.date; ));
    y.domain([0,50]);


    // draw the scatterplot
    svg.selectAll("circle.dot")                                    
        .data(data)                                            
        .enter()
        .append("a")
            .attr("xlink:href", function(d)  return d.link; )
        .append("circle")
          .attr("class", "dot")
            .attr("r", 5)    
            .attr("cx", function(d)  return x(d.date); )         
            .attr("cy", function(d)  return y(d.lala); )
            .attr("fill", function(d) return color(d.flag); )

    // MOUSEOVER EVENTS - Tooltip stuff after this etc
        .on("mouseover", function(d)    

        d3.select(this).transition().duration(50).attr("r", 20).style("opacity", .7); 


            div.transition()
                .duration(500)    
                .style("fill", 0);
            div.transition()
                .duration(200)    
                .style("opacity", 1);    
            div .html(
                d.who + "<br/><b><big>SHOULD</big></b><br/>" + 
                d.what + "..." + "<br/><br/><small>" + 
                formatTime(d.date) + "  [ Section: " + 
                d.flag + " ]</small><br/>")     
                .style("left", 810 + "px")             
                .style("top", 100 + "px");
            )

        .on("mouseout", function()
                d3.select(this).transition().duration(50).attr("r", 5).style("opacity", valOpacity); 
            );

    // Add the X Axis
    svg.append("g")    
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    // Add the Y Axis
    svg.append("g")    
        .attr("class", "y axis")
        .attr("transform", "translate(-30," + 0 + ")")
        .call(yAxis);

);


function handleClick(event)
  currentSearchTerm = document.getElementById("myVal").value;
    console.log(currentSearchTerm);
    draw(currentSearchTerm);
return false;


var valOpacity = function(d)  
      if ((d.what.search(currentSearchTerm) != -1) || (d.who.search(currentSearchTerm) != -1)) 
        return 1;
      
      else 
        return 0.1;
      
    ;

function draw()
    d3.select("body").selectAll("circle.dot").style("opacity", valOpacity);


</script>
</body>

【讨论】:

是的,它就像一个魅力!伟大的!也感谢您抽出宝贵时间来解释它 - 这真的很有帮助! @Sylvia:我很高兴能帮上忙。当您想撤消对搜索词的过滤器时,只需单击按钮删除搜索词,它就会显示所有内容。如果你想给它添加一些香料,你可以添加几行来过渡到过滤的点,伴随着点过渡到更大的圆圈,然后弹回它们的大小。不管怎样,继续努力,享受 d3.js 和 *** 的乐趣吧!

以上是关于使用 HTML 输入在 D3 中进行动态过滤的主要内容,如果未能解决你的问题,请参考以下文章

使用 XMLRPC 在 Python 中进行动态函数调用

如何在 Nuxt 中进行动态导入?

如何在 Struts 2 中进行动态 URL 重定向?

在CodeIgniter中进行动态路由

使用gorm golang在多个表中进行动态列搜索

您如何在 Google 表格中进行动态/依赖下拉菜单?