d3.js 在悬停时传入多个函数 [英] d3.js passing in multiple functions on hover

查看:26
本文介绍了d3.js 在悬停时传入多个函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用了一个教程来在鼠标悬停时获得此功能:

function arcTween(outerRadius, delay) {返回函数(){d3.select(this).transition().delay(delay).attrTween("d", function (d) {var i = d3.interpolate(d.outerRadius,outerRadius);返回函数 (t) { d.outerRadius = i(t);返回弧(d);};});};}

我以这种方式将它添加到饼图的一部分:

.on("mouseover", arcTween(outerRadius, 0, 0))

但是,我还在饼图中的每个切片的 svg 中添加了文本标签,如果您将鼠标悬停在不同的切片上,我希望它们消失.所以我在根据索引创建的时候给了那些标签ID,然后写了这两个方法:

函数可见性显示(数据集大小){for (var i = 0; i < dataSetSize; i++) {$("#" + i).show();}}函数可见性隐藏(索引,数据集大小){for (var i = 0; i < dataSetSize; i++) {如果(我 === 索引){$("#" + i).show();} 别的 {$("#" + i).hide();}}}

现在这些在真空中工作,但是当我尝试将它们放在鼠标悬停事件上时,它不起作用.arcTween 停止工作,i"始终为 0.这些是我尝试过的:

添加另一个 .on("mouseover", ...)

 .on("mouseover", arcTween(outerRadius, 0)).on("鼠标悬停",可见性(0,dataSet.length));

并且还尝试通过以下方式传入索引:

 .on("mouseover", arcTween(outerRadius, 0)).on("mouseover", function (d, i) { return可见性(i, d.length) });

但是除了似乎覆盖了 arcTween() 调用之外,它总是传入 i = 0.

我也试过

.on("mouseover", function (d, i) {返回函数{arcTween(outerRadius, 0);可见性(i, d.length);}})

有人有什么建议吗?(我正在使用 v3,因为所有在线教程都已过时.)

谢谢!

代码片段

//这个数据最终会从 API 调用中收集数据默认 = [];dataController = [{ "label": "Example 1", "value": 1, "child": [{ "label": "Child 1", "value": 1 }] },{ "label": "Example 2", "value": 1, "child": [{ "label": "Child 1", "value": 1 }] },{ "label": "示例 3", "value": 1, "child": [{ "label": "Child 1", "value": 1 }] },{ "label": "Example 4", "value": 1, "child": [{ "label": "Child 1", "value": 1 }] },{ "label": "Example 5", "value": 1, "child": [{ "label": "Child 1", "value": 1 }] }];var displaySize = 20;//这用于跟踪显示的数据var mode = "默认";//SVG 将占用的像素数量无功宽度= 600,高度 = 675;//这是一个甜甜圈,所以它有一个外半径和一个内半径.2r = 宽度所以 r = 宽度/2var 外半径 = 宽度/2,内半径 = 外半径/3;//决定甜甜圈切片颜色的默认颜色函数var 颜色 = d3.scale.category10();//决定甜甜圈切片大小的 pie 函数var pie = d3.layout.pie().value(function (d) { return d["value"]; });//首先我们使用默认数据来创建饼图var pieData = pie(dataDefault);//创建圆弧var arc = d3.svg.arc().innerRadius(innerRadius);//给文档添加一个SVG标签var svg = d3.select("#graphs").append("svg").attr("宽度", 宽度).attr("高度", 高度).append("g").attr("transform", "translate(" + outerRadius + "," + (outerRadius + 50) + ")");//为数据的每个点附加一个链接标签,然后在每个 a 标签内添加一个路径标签svg.selectAll("a").data(pieData).enter().append("a").append("路径").each(function (d) { d.outerRadius = externalRadius - 20; }).attr("d", 弧).attr("fill", function (d, i) { return color(i); }).on("mouseover", arcTween(outerRadius, 0, 0)).on("mouseout", arcTween(outerRadius - 20, 150)).append("标题").text(function (d) { return d["value"] + " hits"; });//将默认数据更改为 Apps 数据,以便在加载时进行动画处理changeToAPI("Controller", dataController);//用于在悬停时增加切片大小的函数函数 arcTween(outerRadius, delay) {返回函数(){d3.select(this).transition().delay(delay).attrTween("d", function (d) {var i = d3.interpolate(d.outerRadius,outerRadius);返回函数 (t) { d.outerRadius = i(t);返回弧(d);};});};}//将色阶传递给更改函数函数 getColor(name) {//得到/3 时的余数var 桶 = hashify(name) % 4;//设置颜色函数数组var 颜色 = [d3.scale.category10(), d3.scale.category20(), d3.scale.category20b(), d3.scale.category20c()];//返回正确的桶返回颜色[桶];}//用于交换显示数据的函数函数 changeToAPI(名称,数据集){//如果数据已经显示,则不更新//JavaScript 不会短路?如果(数据集 === 空){数据集 = [{标签":没有数据...",值":1 }];更改为(名称,数据集);} else if (dataSet.length === 0) {数据集 = [{标签":没有数据...",值":1 }];更改为(名称,数据集);} 别的 {模式=名称;//获取新的饼图和颜色函数var newData = pie(dataSet);var newColor = getColor(name);//移除标签、标题和工具提示svg.selectAll("文本").remove();svg.selectAll("title").remove();//下面的行修复了一个不会导致问题的错误,但会使图形变得丑陋:(svg.selectAll("a").remove();//如果有新切片,则添加var newSlices = svg.selectAll("a").data(newData);newSlices.enter().append("a").append("路径").style("光标", "指针");//更新这些切片的属性并为过渡设置动画newSlices.select("路径").each(function (d) { d.outerRadius = externalRadius - 20; }).过渡().attr("d", 弧).attr("fill", function (d, i) { return newColor(i); }).attr("title", function (d) { return d["value"]; });newSlices.selectAll("路径").on(点击",功能(d){checkForChild(d["data"]["label"], d["data"]);}).on("mouseover.arcExpand", arcTween(outerRadius, 0)).on("mouseover.textHide", function (d, i) {可见性隐藏(我,数据集.长度);}).on("mouseout.arcRetract", arcTween(outerRadius - 20, 150)).on("mouseout.textShow", function (d, i) {可见性显示(数据集.长度);});//去除多余的切片newSlices.exit().remove();//添加标题var title = svg.append("文本").attr("x", 0).attr("y", -(outerRadius + 10)).style("文本锚", "中间").text("+名称+"用法的分布");//添加标签var 标签 = svg.selectAll(null).data(新数据).进入().append("文本").attr(填充",白色").attr("id", function (d, i) { return i }).attr(转换",函数(d){d.innerRadius = 0;d.outerRadius = 外半径;返回 "translate(" + arc.centroid(d) + ")";}).attr(文本锚",中间").text(function (d, i) {返回数据集[i]["标签"];});//添加工具提示svg.selectAll("path").data(newData).append("title").text(function (d) { return d["value"] + " hits"; });svg.append("圆圈").attr("cx", 0).attr("cy", 0).attr("r", 内半径).style("填充", "白色").style("光标", "指针").on("点击", function () {changeToAPI("Controller", dataController);});//如果不在控制器级别,则添加后退按钮如果(数据集!== 数据控制器){svg.append("文本").attr("x", 0).attr("y", 12).style("文本锚", "中间").style("颜色", "#efefef").style("字体大小", "40px").回信");}}}函数更改(名称,数据集){//如果数据已经显示,则不更新//JavaScript 不会短路?如果(数据集 === 空){数据集 = [{标签":没有数据...",值":1 }];} else if (dataSet.length === 0) {数据集 = [{标签":没有数据...",值":1 }];}模式=名称;//获取新的饼图和颜色函数var newData = pie(dataSet);var newColor = getColor(name);//移除标签、标题和工具提示svg.selectAll("文本").remove();svg.selectAll("title").remove();//下面的行修复了一个不会导致问题的错误,但会使图形变得丑陋:(//svg.selectAll("a").remove();//如果有新切片,则添加var newSlices = svg.selectAll("a").data(newData);newSlices.enter().append("a").append("路径").style("光标", "指针");//更新这些切片的属性并为过渡设置动画newSlices.select("路径").each(function (d) { d.outerRadius = externalRadius - 20; }).过渡().attr("fill", function (d, i) { return newColor(i); }).attr("d", 弧).attr("title", function (d) { return d["value"]; });newSlices.selectAll("路径").on("mouseover.arc", arcTween(outerRadius, 0)).on("mouseover.text", function (d, i) {可见性隐藏(我,数据集.长度);}).on("mouseout.arc", arcTween(outerRadius - 20, 150)).on("mouseout.text", 函数 (d, i) {可见性显示(数据集.长度);});//去除多余的切片newSlices.exit().remove();//添加标题svg.append("文本").attr("x", 0).attr("y", -(outerRadius + 10)).style("文本锚", "中间").text(function (e) {var title = "" + 名称 + " 用法的分布";if (name === "默认") {title = "加载中..."}返回标题;});//添加标签svg.selectAll(null).data(新数据).进入().append("文本").attr(填充",白色").attr("id", function (d, i) { return i }).attr(转换",函数(d){d.innerRadius = 0;d.outerRadius = 外半径;返回 "translate(" + arc.centroid(d) + ")";}).attr(文本锚",中间").text(function (d, i) {返回数据集[i]["标签"];});//添加工具提示svg.selectAll("path").data(newData).append("title").text(function (d) { return d["value"] + " hits"; });}函数 checkForChild(名称,数据集){如果(dataSet.hasOwnProperty(孩子")){if (dataSet["child"] !== null) {if (dataSet["child"].length !== 0) {changeToAPI(name, dataSet["child"]);}}}}//字符串的哈希码生成器函数散列(字符串){无功哈希= 0;//将每个字符的值与哈希值相加for (var i = 0; i < string.length; i++) {hash += string.charCodeAt(i);}返回哈希值;}功能可见性显示(数据集大小){for (var i = 0; i < dataSetSize; i++) {$("#" + i).show();}}函数可见性隐藏(索引,数据集大小){for (var i = 0; i < dataSetSize; i++) {如果(我 === 索引){$("#" + i).show();} 别的 {$("#" + i).hide();}}}

body {字体系列:Arial;过渡:全部轻松 0.5 秒;文本对齐:居中;颜色:RGB(58,58,58);}

<头><meta name="viewport" content="width=device-width"/><script src="https://d3js.org/d3.v3.min.js"></script><script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script><title>一般统计</title><身体><div id="图形">

</html>

解决方案

如果您在同一个选择中有多个相同类型的事件侦听器,则必须命名空间您的事件侦听器(但这可能无法解决您的问题,请进一步阅读Post Scriptum.

现在的问题,正如@AndrewReid 在他的注释,是下一个事件监听器移除前一个事件监听器.根据 API:

<块引用>

如果已在所选元素上为相同类型注册了事件侦听器,则在添加新侦听器之前删除现有侦听器.

让我们在下面的演示中看到它.

由于你没有提供你的工作代码,我在这里创建了一个简单的,有两个事件监听器:第一个增加圆圈,第二个淡出文本:

.on("mouseover", increaseCircle)//这个不行!.on("mouseover",fadeText)//只有这个能用...

你可以看到只有最后一个有效:

var svg = d3.select("svg");var circle = svg.append("circle").attr("r", 20).attr("cx", 100).attr("cy", 50).attr(填充",棕褐色").attr(中风",黑色").on("鼠标悬停",增加Circle).on("鼠标悬停",fadeText).on("mouseout", function() {circle.transition().duration(500).attr("r", 20);text.transition().duration(500).style("opacity", 1);})var text = svg.append("文本").attr("y", 55).attr("x", 150).style("font-family", "helvetica").text("悬停在圆圈上");函数增加Circle(){circle.transition().duration(500).attr("r", 40)}函数淡入淡出(){text.transition().duration(500).style("opacity", 0)}

<script src="https://d3js.org/d3.v3.js"></script><svg></svg>

解决方案:

不过,有一个非常简单的解决方案.根据相同的 API:

<块引用>

为同一个事件类型注册多个监听器,类型后面可以跟一个可选的命名空间,比如click.foo"和click.bar"

因此,在上面的演示中,我们只需要这样的东西:

.on("mouseover.circle", increaseCircle).on("mouseover.text",fadeText)

这是演示,两个事件侦听器都可以工作:

var svg = d3.select("svg");var circle = svg.append("circle").attr("r", 20).attr("cx", 100).attr("cy", 50).attr(填充",棕褐色").attr(中风",黑色").on("mouseover.circle", 增加Circle).on("mouseover.text",fadeText).on("mouseout", function() {circle.transition().duration(500).attr("r", 20);text.transition().duration(500).style("opacity", 1);})var text = svg.append("文本").attr("y", 55).attr("x", 150).style("font-family", "helvetica").text("悬停在圆圈上");函数增加Circle(){circle.transition().duration(500).attr("r", 40)}函数淡入淡出(){text.transition().duration(500).style("opacity", 0)}

<script src="https://d3js.org/d3.v3.js"></script><svg></svg>

当然,一个简单的替代方案就是:

selection.on("mouseover", function(){富();酒吧();巴兹();等等...});

<小时>

PS:以上答案涉及命名空间问题.但是,除此之外,您的代码还有一些问题,我们无法测试,因为您没有提供工作演示.

第一个问题:当你这样做时......

.on("mouseover", arcTween(outerRadius, 0, 0))

...您正在立即调用 arcTween,并将其值传递给侦听器.你可能想要:

.on("mouseover", function(){ arcTween(outerRadius, 0, 0)})

其次,这是不正确的:

.on("mouseover", function (d, i) {返回函数{arcTween(outerRadius, 0);可见性(i, d.length);}})

应该只是:

.on("mouseover", function (d, i) {arcTween(outerRadius, 0);可见性(i, d.length);})

I used a tutorial to get this function on mouseover:

function arcTween(outerRadius, delay) {
    return function () {
        d3.select(this).transition().delay(delay).attrTween("d", function (d) {
            var i = d3.interpolate(d.outerRadius, outerRadius);
            return function (t) { d.outerRadius = i(t); return arc(d); };
        });
    };
} 

And I add it to parts of a pie chart this way:

.on("mouseover", arcTween(outerRadius, 0, 0))

However, I also have text tags added to svg for each slice in the pie chart, and want those to fade away if you are hovering over a different slice. So I gave those tags IDs when I create them based on the index, then wrote these two methods:

function visibilityShow(dataSetSize) {
    for (var i = 0; i < dataSetSize; i++) {
        $("#" + i).show();
    }
}

function visibilityHide(index, dataSetSize) {
    for (var i = 0; i < dataSetSize; i++) {
        if (i === index) {
            $("#" + i).show();
        } else {
            $("#" + i).hide();
        }
    }
}

Now these work in a vacuum, but when I try to put them on a mouseover event, it won't work. arcTween stops working, and "i" is always 0. These were what I tried:

Adding another .on("mouseover", ...)

        .on("mouseover", arcTween(outerRadius, 0))
        .on("mouseover", visibility(0, dataSet.length));

and also tried passing in the index with:

        .on("mouseover", arcTween(outerRadius, 0))
        .on("mouseover", function (d, i) { return visibility(i, d.length) });

But that always passes in i = 0 in addition to seemingly overwriting the arcTween() call.

I also tried

.on("mouseover", function (d, i) {
     return function {
          arcTween(outerRadius, 0);
          visibility(i, d.length);
     }
})

Anyone have any advice? (I'm using v3 because all the tutorials online are outdated.)

Thanks!

EDIT: Code Snippet

// This data will be gathered from API calls eventually
dataDefault = [];
dataController = [{ "label": "Example 1", "value": 1, "child": [{ "label": "Child 1", "value": 1 }] },
                  { "label": "Example 2", "value": 1, "child": [{ "label": "Child 1", "value": 1 }] },
                  { "label": "Example 3", "value": 1, "child": [{ "label": "Child 1", "value": 1 }] },
                  { "label": "Example 4", "value": 1, "child": [{ "label": "Child 1", "value": 1 }] },
                  { "label": "Example 5", "value": 1, "child": [{ "label": "Child 1", "value": 1 }] }];

var displaySize = 20;

// This is used to keep track of what data is showing
var mode = "Default";

// The amount of pixels the SVG will take up
var width = 600,
    height = 675;

// It's a donut, so it has an outer radius and an inner radius. 2r = width so r = width/2
var outerRadius = width / 2,
    innerRadius = outerRadius / 3;

// Default color function for deciding the colros of the donut slices
var color = d3.scale.category10();

// The pie function for deciding the size of the donut slices
var pie = d3.layout.pie()
    .value(function (d) { return d["value"]; });

// At first we use the default data to create the pie
var pieData = pie(dataDefault);

// Create an arc
var arc = d3.svg.arc()
    .innerRadius(innerRadius);

// Add an SVG tag to the document
var svg = d3.select("#graphs").append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
  .attr("transform", "translate(" + outerRadius + "," + (outerRadius + 50) + ")");

// Append an link tag for each point of the data, then add an path tag inside each a tag
svg.selectAll("a")
    .data(pieData)
  .enter().append("a")
    .append("path")
    .each(function (d) { d.outerRadius = outerRadius - 20; })
    .attr("d", arc)
    .attr("fill", function (d, i) { return color(i); })
    .on("mouseover", arcTween(outerRadius, 0, 0))
    .on("mouseout", arcTween(outerRadius - 20, 150))
        .append("title")
        .text(function (d) { return d["value"] + " hits"; });

// Change the default data to the Apps data so it animates on load
changeToAPI("Controller", dataController);

// Function used to increase slice size on hover
function arcTween(outerRadius, delay) {
    return function () {
        d3.select(this).transition().delay(delay).attrTween("d", function (d) {
            var i = d3.interpolate(d.outerRadius, outerRadius);
            return function (t) { d.outerRadius = i(t); return arc(d); };
        });
    };
}

// Passes the color scale into the change function
function getColor(name) {
    // Get the remainder when / 3
    var bucket = hashify(name) % 4;

    // Setup the array of color functions
    var colors = [d3.scale.category10(), d3.scale.category20(), d3.scale.category20b(), d3.scale.category20c()];

    // Return the correct bucket
    return colors[bucket];
}

// Function used to swap the data being shown
function changeToAPI(name, dataSet) {
    // Don't update if the data is already showing

    // JavaScript doesn't short circuit?
    if (dataSet === null) {
        dataSet = [{ "label": "No data...", "value": 1 }];
        changeTo(name, dataSet);
    } else if (dataSet.length === 0) {
        dataSet = [{ "label": "No data...", "value": 1 }];
        changeTo(name, dataSet);
    } else {

        mode = name;

        // Get the new pie and color functions
        var newData = pie(dataSet);
        var newColor = getColor(name);

        // Remove the labels, titles, and tooltips
        svg.selectAll("text").remove();
        svg.selectAll("title").remove();
        // Line below fixes an error that doesn't cause issues, but makes the graph ugly :(
        svg.selectAll("a").remove();

        // Add the new slices if there are any
        var newSlices = svg.selectAll("a")
                            .data(newData);

        newSlices.enter()
            .append("a")
                .append("path")
                .style("cursor", "pointer");

        // Update the attributes of those slices and animate the transition
        newSlices.select("path")
                .each(function (d) { d.outerRadius = outerRadius - 20; })
                .transition()
                .attr("d", arc)
                .attr("fill", function (d, i) { return newColor(i); })
                .attr("title", function (d) { return d["value"]; });

        newSlices.selectAll("path")
                    .on("click", function (d) {
                        checkForChild(d["data"]["label"], d["data"]);
                    })
                    .on("mouseover.arcExpand", arcTween(outerRadius, 0))
                    .on("mouseover.textHide", function (d, i) {
                        visibilityHide(i, dataSet.length);
                    })
                    .on("mouseout.arcRetract", arcTween(outerRadius - 20, 150))
                    .on("mouseout.textShow", function (d, i) {
                        visibilityShow(dataSet.length);
                    });

        // Remove excess slices
        newSlices.exit().remove();

        // Add a title
        var title = svg.append("text")
            .attr("x", 0)
            .attr("y", -(outerRadius + 10))
            .style("text-anchor", "middle")
            .text("Distrubution of " + name + " Usage");

        // Add labels
        var labels = svg.selectAll(null)
            .data(newData)
            .enter()
                .append("text")
                .attr("fill", "white")
                .attr("id", function (d, i) { return i })
                .attr("transform", function (d) {
                    d.innerRadius = 0;
                    d.outerRadius = outerRadius;
                    return "translate(" + arc.centroid(d) + ")";
                })
                .attr("text-anchor", "middle")
                .text(function (d, i) {
                    return dataSet[i]["label"];
                });

        // Add tooltips
        svg.selectAll("path").data(newData).append("title").text(function (d) { return d["value"] + " hits"; });

        svg.append("circle")
        .attr("cx", 0)
        .attr("cy", 0)
        .attr("r", innerRadius)
        .style("fill", "white")
        .style("cursor", "pointer")
        .on("click", function () {
            changeToAPI("Controller", dataController);
        });

        // Adds back button if not at controller level
        if (dataSet !== dataController) {
            svg.append("text")
                .attr("x", 0)
                .attr("y", 12)
                .style("text-anchor", "middle")
                .style("color", "#efefef")
                .style("font-size", "40px")
                .text("Back");
        }
    }
}

function changeTo(name, dataSet) {
    // Don't update if the data is already showing

    // JavaScript doesn't short circuit?
    if (dataSet === null) {
        dataSet = [{ "label": "No data...", "value": 1 }];
    } else if (dataSet.length === 0) {
        dataSet = [{ "label": "No data...", "value": 1 }];
    }

    mode = name;

    // Get the new pie and color functions
    var newData = pie(dataSet);
    var newColor = getColor(name);

    // Remove the labels, titles, and tooltips
    svg.selectAll("text").remove();
    svg.selectAll("title").remove();
    // Line below fixes an error that doesn't cause issues, but makes the graph ugly :(
    //svg.selectAll("a").remove();

    // Add the new slices if there are any
    var newSlices = svg.selectAll("a")
                        .data(newData);

    newSlices.enter()
        .append("a")
            .append("path")
            .style("cursor", "pointer");

    // Update the attributes of those slices and animate the transition
    newSlices.select("path")
            .each(function (d) { d.outerRadius = outerRadius - 20; })
            .transition()
            .attr("fill", function (d, i) { return newColor(i); })
            .attr("d", arc)
            .attr("title", function (d) { return d["value"]; });

    newSlices.selectAll("path")
                .on("mouseover.arc", arcTween(outerRadius, 0))
                .on("mouseover.text", function (d, i) {
                    visibilityHide(i, dataSet.length);
                 })
                .on("mouseout.arc", arcTween(outerRadius - 20, 150))
                .on("mouseout.text", function (d, i) {
                    visibilityShow(dataSet.length);
                });

    // Remove excess slices
    newSlices.exit().remove();

    // Add a title
    svg.append("text")
        .attr("x", 0)
        .attr("y", -(outerRadius + 10))
        .style("text-anchor", "middle")
        .text(function (e) {
            var title = "Distrubution of " + name + " Usage";
            if (name === "Defualt") {
                title = "Loading..."
            }
            return title;
        });

    // Add labels
    svg.selectAll(null)
        .data(newData)
        .enter()
            .append("text")
            .attr("fill", "white")
            .attr("id", function (d, i) { return i })
            .attr("transform", function (d) {
                d.innerRadius = 0;
                d.outerRadius = outerRadius;
                return "translate(" + arc.centroid(d) + ")";
            })
            .attr("text-anchor", "middle")
            .text(function (d, i) {
                return dataSet[i]["label"];
            });

    // Add tooltips
    svg.selectAll("path").data(newData).append("title").text(function (d) { return d["value"] + " hits"; });
}

function checkForChild(name, dataSet) {
    if (dataSet.hasOwnProperty("child")) {
        if (dataSet["child"] !== null) {
            if (dataSet["child"].length !== 0) {
                changeToAPI(name, dataSet["child"]);
            }
        }
    }
}

// Hashcode generator for strings
function hashify(string) {
    var hash = 0;

    // Add the value of each char to the hash value
    for (var i = 0; i < string.length; i++) {
        hash += string.charCodeAt(i);
    }

    return hash;
}

function visibilityShow(dataSetSize) {
    for (var i = 0; i < dataSetSize; i++) {
        $("#" + i).show();
    }
}

function visibilityHide(index, dataSetSize) {
    for (var i = 0; i < dataSetSize; i++) {
        if (i === index) {
            $("#" + i).show();
        } else {
            $("#" + i).hide();
        }
    }
}

body {
    font-family: Arial;
    transition: all ease .5s;
    text-align: center;
    color: rgb(58,58,58);
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <script src="https://d3js.org/d3.v3.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <title>General Statistics</title>
</head>
<body>
    <div id="graphs">
    </div>
</body>
</html>

解决方案

If you have more than one event listener of the same type in the same selection, you have to namespace your event listeners (but this probably won't fix your issue, please also read the Post Scriptum further down).

The problem right now, as @AndrewReid explained in his comment, is that the next event listener removes the previous one. According to the API:

If an event listener was already registered for the same type on the selected element, the existing listener is removed before the new listener is added.

Let's see it in the following demo.

Since you didn't provide your working code, I create a simple one here, with two event listeners: the first one increases the circle, and the second one fades out the text:

.on("mouseover", increaseCircle)//this one will not work!
.on("mouseover", fadeText)//only this one will work...

You can see that only the last one works:

var svg = d3.select("svg");

var circle = svg.append("circle")
  .attr("r", 20)
  .attr("cx", 100)
  .attr("cy", 50)
  .attr("fill", "tan")
  .attr("stroke", "black")
  .on("mouseover", increaseCircle)
  .on("mouseover", fadeText)
  .on("mouseout", function() {
    circle.transition().duration(500).attr("r", 20);
    text.transition().duration(500).style("opacity", 1);
  })

var text = svg.append("text")
  .attr("y", 55)
  .attr("x", 150)
  .style("font-family", "helvetica")
  .text("Hover over the circle");

function increaseCircle() {
  circle.transition().duration(500).attr("r", 40)
}

function fadeText() {
  text.transition().duration(500).style("opacity", 0)
}

<script src="https://d3js.org/d3.v3.js"></script>
<svg></svg>

Solution:

There is a very simple solution, though. According to the same API:

To register multiple listeners for the same event type, the type may be followed by an optional namespace, such as "click.foo" and "click.bar"

Thus, in the above demo, we just need something like this:

.on("mouseover.circle", increaseCircle)
.on("mouseover.text", fadeText)

Here is the demo, both event listeners work:

var svg = d3.select("svg");

var circle = svg.append("circle")
  .attr("r", 20)
  .attr("cx", 100)
  .attr("cy", 50)
  .attr("fill", "tan")
  .attr("stroke", "black")
  .on("mouseover.circle", increaseCircle)
  .on("mouseover.text", fadeText)
  .on("mouseout", function() {
    circle.transition().duration(500).attr("r", 20);
    text.transition().duration(500).style("opacity", 1);
  })

var text = svg.append("text")
  .attr("y", 55)
  .attr("x", 150)
  .style("font-family", "helvetica")
  .text("Hover over the circle");

function increaseCircle() {
  circle.transition().duration(500).attr("r", 40)
}

function fadeText() {
  text.transition().duration(500).style("opacity", 0)
}

<script src="https://d3js.org/d3.v3.js"></script>
<svg></svg>

Of course, a simple alternative to all this is just:

selection.on("mouseover", function(){
    foo();
    bar();
    baz();
    etc...
});


PS: The above answer deals with the namespace issue. However, besides that issue, your code has a couple of problems, which we cannot test because you didn't provide a working demo.

First problem: when you do this...

.on("mouseover", arcTween(outerRadius, 0, 0))

... you are calling arcTween immediately, and passing its value to the listener. You probably want:

.on("mouseover", function(){ arcTween(outerRadius, 0, 0)})

Second, this is not correct:

.on("mouseover", function (d, i) {
    return function {
        arcTween(outerRadius, 0);
        visibility(i, d.length);
    }
})

It should be just:

.on("mouseover", function (d, i) {
    arcTween(outerRadius, 0);
    visibility(i, d.length);
})

这篇关于d3.js 在悬停时传入多个函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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