点击表,更新行,悬停在行,更新表 [英] Click table, update line, hover over line, update table

查看:111
本文介绍了点击表,更新行,悬停在行,更新表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是D3的新手,但是至今还是喜欢它。但我知道我的解决方案缺乏...优雅。



我试图有2个控件,一个表和一个图形,显示由表格的单元格表示的数据。如果单击表上的单元格,则相关联的行应突出显示。如果将鼠标悬停在一行上,关联表单元格将更改颜色。最终,将存在显示该cel特定的细节数据的第三控件。不幸的是,我只有设法使这项工作,如果我使用静态调用更新功能。如果我试图聪明和动态的整个事情打破。



我试图尽量减少我的例子尽可能多,我可以在下面。点击表 - >更新行工作,因为对SelectData()的调用更新一切都使用常量数据。然而鼠标悬停在线上不工作。最后,我需要表更具动态性,但是现在,我该如何解决这个问题?

 <!DOCTYPE html> ; 
< meta charset =utf-8>
< style>
.lineDefault {
fill:none;
stroke:red;
stroke-width:1.5px;
stroke-dasharray:4,4;
}
.axis路径,
.axis行{
fill:none;
stroke:#000;
shape-rendering:crispEdges;
}
< / style>
< body>
< div id =wrap>
< table>
< tr>
< td id =dataBlockonclick =SelectData(0)> 1< / td>
< td id =dataBlockonclick =SelectData(1)> 2< / td>
< / tr>
< tr>
< td id =dataBlockonclick =SelectData(2)> 3< / td>
< td id =dataBlockonclick =SelectData(3)> 4< / td>
< / tr>
< / table>
< div>
< svg class =chart>< / svg>
< / div>
< / div>
< script src =http://d3js.org/d3.v3.min.js>< / script>
< script>
var width = 600,height = 600;
var maxx = 100,
maxy = 100;

var linedata = {};
linedata [0] = [[0,50],[50,60],[100,100]];
linedata [1] = [[0,40],[40,40],[100,90]];
linedata [2] = [[0,20],[50,30],[100,90]];
linedata [3] = [[0,0],[60,30],[100,30]];
var activeElement = 0;
var graphlines = {};
var numlines = 0;

chart = d3.select(。chart)。attr(viewBox,0 0 600 600)append(g);

var x = d3.scale.linear()。domain([0,maxx])。range([0,width]);

var y = d3.scale.linear()。domain([0,maxy])。range([height,0]);

var xAxis = d3.svg.axis()。scale(x).orient(bottom);

var yAxis = d3.svg.axis()。scale(y).orient(left);

var line = d3.svg.line()
.x(function(d){return x(d [0]);})
.y d){return y(d [1]);});

for(var i = 0; i <4; i ++){
graphlines [i] = chart
.append(path)
。 (linedata [i])
.attr(class,lineDefault)
.attr(id,linedata)
.attr b $ b .on(mouseover,SelectData(i));
numlines ++;
}

function selectData(n){
d3.selectAll(td)。transition()
.style(background-color d,i){
return i == n?#c99:#fff;
});
activeElement = n;
for(var i = 0; i if(i == n){
graphlines [i]
.style(stroke-dasharray ,1,0)
.transition()
.style(stroke-width,3)
.style(stroke,steelblue);
} else {
graphlines [i]
.style(stroke-dasharray,4,4)
.transition()
.style stroke-width,1.5)
.style(stroke,red);
}
}
}

< / script>

表上的mouseclick会影响行,鼠标悬停在行上不会影响表。

解决方案

首先,鼠标悬停方法的原因是 t工作是因为在这一行:

  .on(mouseover,SelectData(i)); code <$>           .on()方法。因此,当您完成初始化时,您的最后一个项目被选中,但没有监听mouseover事件的函数。你想要的是将函数 name 传递给 .on()方法。如果您使该函数采用两个参数(通常命名为 d  i ), d3将自动传递索引值作为第二个参数。我写了一个相当长的讨论,关于传递函数作为参数为别人最近,你可能会发现它有用



此外,你真的没有利用d3选择结构,它可以在一个调用中使用 -loops做。我建议花时间阅读一些教程,了解d3选择的工作原理。



现在,针对您的主要问题:



通常的解决方案是选择数据与点击的元素是给所有元素基于数据中的唯一ID的类。然后,您可以轻松地选择与给定数据对象相关联的所有元素。如果用户选择了一个 d.name = Sue 的对象,并且初始化了具有该名称的所有元素作为类名,那么您可以 d3.select(path.Sue)以及 d3.select(td.Sue)才能找到正确的。 p>

您的示例数据似乎没有任何唯一的数据ID值,只是索引号。因此,您甚至不需要一个独特的类,只需使用 nth-of-type(i + 1) CSS选择器。 ( i + 1 ,因为CSS计数从1开始,而数据计数从0开始。)



但是,我建议您使用一个特殊的CSS类来应用所有的突出显示样式。这样,很容易选择当前突出显示的值来删除该类,而不必循环遍历所有内容以测试它是否匹配。您可以使用CSS转换来在类更改后转换样式。



这里是一个小小的版本的代码,整理了正确使用d3和上面的方法数据。



http://fiddle.jshell.net/g8z5h /



我尚未实现您的表格的实时版本,但我建议您阅读嵌套选择教程,以了解如何工作。



我给每个数据块都有自己的行,所以 nth-of-type() (元素的CSS编号仅在它们都是兄弟元素的情况下有效,它们不能是跨多行划分的表数据元素)。如果你需要原始的布局工作,你必须根据他们的索引值给元素类名,并使用那些选择。我也将点击事件绑定移动到代码中,因为JSFiddle将所有的代码包装在一个窗口加载事件中,所以SelectData函数在其外部不可见。


I'm new to D3, but loving it so far. But I know my solutions lack... elegance.

I am trying to have 2 controls, a table and a graph displaying the data represented by the cells of the table. If you click on a cell on the table, the associated line should be highlighted. If you hover over a line the associate table cell will change color. Eventually there will be a third control showing detail data specific to that cel. Unfortunately I've only managed to make this work if I use static calls to the update function. If I try to be clever and dynamic the whole thing breaks.

I've tried to minimize my example as much as I can below. The click table->update line works because the calls to SelectData() that updates everything uses constant data. However the mouseover on the lines doesn't work. Eventually I need the table to be more dynamic too, but for now, how do I fix this?

<!DOCTYPE html>
<meta charset="utf-8">
<style>
    .lineDefault {
        fill: none;
        stroke: red;
        stroke-width: 1.5px;
        stroke-dasharray: 4,4;
    }
    .axis path,
    .axis line {
        fill: none;
        stroke: #000;
        shape-rendering: crispEdges;
    }
</style>
<body>
    <div id="wrap">
        <table>
            <tr>
                <td id="dataBlock" onclick="SelectData(0)">1</td>
                <td id="dataBlock" onclick="SelectData(1)">2</td>
            </tr>
            <tr>
                <td id="dataBlock" onclick="SelectData(2)">3</td>
                <td id="dataBlock" onclick="SelectData(3)">4</td>
            </tr>
        </table>
        <div>
            <svg class="chart"></svg>
        </div>
    </div>
    <script src="http://d3js.org/d3.v3.min.js"></script>
<script>
    var width = 600, height = 600;
    var maxx = 100,
        maxy = 100;

    var linedata = {};
    linedata[0] = [[0, 50 ],[ 50, 60 ],[100, 100]];
    linedata[1] = [[0, 40 ],[ 40, 40 ],[100, 90 ]];
    linedata[2] = [[0, 20 ],[ 50, 30 ],[100, 90 ]];
    linedata[3] = [[0, 0  ],[ 60, 30 ],[100, 30 ]];
    var activeElement = 0;
    var graphlines = {};
    var numlines = 0;

    chart = d3.select(".chart").attr("viewBox", "0 0 600 600").append("g");

    var x = d3.scale.linear().domain([0, maxx]).range([0, width]);

    var y = d3.scale.linear().domain([0, maxy]).range([height, 0]);

    var xAxis = d3.svg.axis().scale(x).orient("bottom");

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

    var line = d3.svg.line()
        .x(function(d) { return x(d[0]); })
        .y(function(d) { return y(d[1]); });

    for (var i = 0; i < 4; i++) {
        graphlines[i] = chart
            .append("path")
            .datum(linedata[i])
            .attr("class", "lineDefault")
            .attr("id", "linedata")
            .attr("d", line)
            .on("mouseover", SelectData(i));
        numlines++;
    }

    function SelectData(n) {
        d3.selectAll("td").transition()
            .style("background-color", function(d, i) {
                return i == n ? "#c99" : "#fff";
            });
        activeElement = n;
        for (var i = 0; i<numlines; i++) {
            if (i == n) {
                graphlines[i]
                    .style("stroke-dasharray", "1,0")
                    .transition()
                    .style("stroke-width", "3")
                    .style("stroke", "steelblue");
            } else {
                graphlines[i]
                    .style("stroke-dasharray", "4,4")
                    .transition()
                    .style("stroke-width", "1.5")
                    .style("stroke", "red");
            }
        }
    }

</script>

The mouseclick on the table effects the lines, the mouseover on the lines does not effect the table. Also I will accept any berating on my elegance and pointers to fixing them.

解决方案

First, the reason why your mouseover method wasn't working is because in this line:

        .on("mouseover", SelectData(i));

you are calling the SelectData method at the time you call the .on() method. So when you're done initializing, your last item is selected, but there is no function listening to the mouseover event. What you want is to pass the function name to the .on() method. If you make that function take two parameters (usually named d and i), then d3 will automatically pass the index value as the second parameter. I wrote up a rather long discussion about passing functions as parameters for someone else recently, you may find it useful.

Furthermore, you're really not taking advantage of the d3 selection structure, which can do in one call all the things you're using for-loops to do. I'd suggest taking the time to read through some tutorials on how the d3 selections work.

Now, to your main question:

The usual solution for selecting an element whose data matches the data of a clicked element is to give all elements a class based on a unique ID from the data. Then you can easily select all the elements associated with a given data object. If the user selects an object with d.name=Sue, and you initialized all the elements with that name as a class name, then you can do d3.select("path.Sue") and also d3.select("td.Sue") to find the correct ones.

Your example data doesn't seem to have any unique data id value, just the index number. So you don't even need a unique class, you can just use the nth-of-type(i+1) CSS selector. (It's i+1 because the CSS counting starts at 1, while the data count starts at 0.)

However, I would suggest that you use a special CSS class to apply all your highlighting styles. That way, it will be easy to select the currently highlighted values to remove that class, instead of having to loop through everything to test whether or not it matches. You can use CSS transitions to transition the style after a class changes.

Here's a fiddle version of your code, tidied up to use d3 properly and with the above method for highlighting data.

http://fiddle.jshell.net/g8z5h/

I haven't implemented the live version of your table, but I recommend you read the tutorial on nested selections to figure out how that will work.

I did give each data block it's own row so that the nth-of-type() selector would work properly (the CSS numbering of elements only works if they are all siblings, they can't be table data elements split across multiple rows). If you need the original layout to work, you'll have to give elements class names based on their index value, and use those to select. I also moved the click event binding into the code, because JSFiddle wraps all its code in a window load event, so the SelectData function wasn't visible outside it.

这篇关于点击表,更新行,悬停在行,更新表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆