Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/401.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript D3.js中的鼠标悬停问题,包含路径元素,并在焦点刷过后更改工具提示数据?_Javascript_Jquery_Css_Svg_D3.js - Fatal编程技术网

Javascript D3.js中的鼠标悬停问题,包含路径元素,并在焦点刷过后更改工具提示数据?

Javascript D3.js中的鼠标悬停问题,包含路径元素,并在焦点刷过后更改工具提示数据?,javascript,jquery,css,svg,d3.js,Javascript,Jquery,Css,Svg,D3.js,我在一个多系列、焦点+背景D3图表中遇到了以下问题,我想我会尝试一次性得到我主要问题的答案 我的问题如下: 如何确保我创建的工具提示不受图表的发际线(位于鼠标之后)的影响,即不消失,而是一直持续到移动鼠标为止?这就是如果发际线不可见或已创建,它们的行为方式 出于某种原因(可能很明显,但对我来说并不明显),数据的路径并不局限于焦点区域,而是溢出到图表的左侧。如何解决这个问题?我意识到这可能与左边距有关 最后,当数据被刷新时,焦点图表会通过上下文进行更新,但我很难更新工具提示数据。有人能看到现有代码

我在一个多系列、焦点+背景D3图表中遇到了以下问题,我想我会尝试一次性得到我主要问题的答案

我的问题如下:

  • 如何确保我创建的工具提示不受图表的发际线(位于鼠标之后)的影响,即不消失,而是一直持续到移动鼠标为止?这就是如果发际线不可见或已创建,它们的行为方式

  • 出于某种原因(可能很明显,但对我来说并不明显),数据的路径并不局限于焦点区域,而是溢出到图表的左侧。如何解决这个问题?我意识到这可能与左边距有关

  • 最后,当数据被刷新时,焦点图表会通过上下文进行更新,但我很难更新工具提示数据。有人能看到现有代码有什么问题吗

  • CSS:

            body {
              font: 10px sans-serif;
            }
    
            .axis path,
            .axis path_steelblue {
                fill: none;
                stroke: #000;
                shape-rendering: geometricPrecision;
            }
    
            .path_steelblue {
                fill: none;
                stroke: steelblue;
                stroke-width: 1.5px;
            }
    
            .path_blue {
                fill: none;
                stroke: #3333FF;
                stroke-width: 1.5px;
            }
            .path_red {
                fill: none;
                stroke:red;
                stroke-width: 1.5px;
            }
            .path_yellow {
                fill: none;
                stroke:yellow;
                stroke-width: 1.5px;
            }
    
            .brush .extent {
                stroke: #FFF;
                fill-opacity: .125;
                shape-rendering: crispEdges;
            }
    
            .axis path,
            .axis line {
                fill: none;         
                stroke: grey;       
                stroke-width: 1;     
                shape-rendering: crispEdges;
            }
            .grid .tick {
                stroke: lightgrey;
                opacity: 0.7;
                shape-rendering: crispEdges;
            }
            .grid path {
                stroke-width: 0;
                shape-rendering: crispEdges;
            }
    
            .dot {
                fill: white;
                stroke: white;
                opacity:0.01;
                stroke-width: 0px;
                cursor:crosshair;
            }
    
            div.tooltip {   
                position: absolute;           
                text-align: left;           
                width: 120px;                  
                height: 48px;                 
                padding: 10px;             
                font: 12px sans-serif;        
                background: steelblue;   
                border: 0px;      
                border-radius: 8px;           
                pointer-events: none;
            }
    
            div.tooltipSolvency {       
                background: #3333FF;
            }
    
            div.tooltipTechnical {       
                background: red;
            }
    
            div.tooltipAccounting {       
                background: yellow;
            }
    
            .hover-line { 
                stroke: #000;
                fill: none;
                stroke-width: 1px;
                left: 10px;
                shape-rendering: crispEdges;
            }
    
            .hover-text {
                stroke: none;
                font-size: 12px;
                font-weight: bold;
                fill: #000000;
            }
    
    D3代码:

            var margin = { top: 10, right: 10, bottom: 100, left: 40 },
                margin2 = { top: 430, right: 10, bottom: 20, left: 40 },
                width = 960 - margin.left - margin.right,
                height = 500 - margin.top - margin.bottom,
                height2 = 500 - margin2.top - margin2.bottom;
    
            var parseDate = d3.time.format("%Y-%m-%dT%H:%M:%S").parse;
            var formatTime = d3.time.format("%d/%m/%Y");
    
            var x = d3.time.scale().range([0, width]),
                x2 = d3.time.scale().range([0, width]),
                y = d3.scale.linear().range([height, 0]),
                y2 = d3.scale.linear().range([height2, 0]);
    
            var xAxis = d3.svg.axis().scale(x).orient("bottom"),
                xAxis2 = d3.svg.axis().scale(x2).orient("bottom"),
                yAxis = d3.svg.axis().scale(y).orient("left");
    
            var brush = d3.svg.brush()
                .x(x2)
                .on("brush", brushed);
    
            var line = d3.svg.line()
                .x(function(d) { return x(d.date); })
                .y(function(d) { return y(d.chartValue); });
    
            var line2 = d3.svg.line()
                .x(function(d) { return x2(d.date); })
                .y(function(d) { return y2(d.chartValue); });
    
            var svg = d3.select(".tracker-chart").append("svg")
                .attr("width", width + margin.left + margin.right)
                .attr("height", height + margin.top + margin.bottom);
                //.style("margin-left", "40px")
                //.style("margin-top", "40px");
    
            //var container = svg.append("g")
            //  .attr("width", width + margin.left + margin.right)
            //  .attr("height", height + margin.top + margin.bottom);
    
            svg.append("defs").append("clipPath")
                .attr("id", "clip")
              .append("rect")
                .attr("width", width)
                .attr("height", height);
    
            var focus = svg.append("g")
                .attr("class", "focus")
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
            // Hover line. 
            var hoverLineGroup = svg.append("g") //svg.append("g") -- Ensures hairline follows mouse pointer put interferes with the tooltip not allowing it to persist until the mouse moves again
                .attr("class", "hover-line");
    
            var hoverLine = hoverLineGroup
                .append("line")
                    .attr("x1", 10).attr("x2", 10) 
                    .attr("y1", 0).attr("y2", height + 10);
    
            var hoverDate = hoverLineGroup.append('text')
                .attr("class", "hover-text")
                .attr('y', height - (height-10));
    
            // Hide hover line by default.
            hoverLine.style("opacity", 1e-6);
    
            var div = d3.select(".tracker-chart").append("div")
                .attr("class", "tooltip")
                .style("opacity", 0);
    
            var divSolvency = d3.select(".tracker-chart").append("div")
                .attr("class", "tooltip tooltipSolvency")
                .style("opacity", 0);
    
            var divTechnical = d3.select(".tracker-chart").append("div")
                .attr("class", "tooltip tooltipTechnical")
                .style("opacity", 0);
    
            var divAccounting = d3.select(".tracker-chart").append("div")
                .attr("class", "tooltip tooltipAccounting")
                .style("opacity", 0);
    
            var context = svg.append("g")
                .attr("class", "context")
                .attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
    
            d3.xml("data.xml", "application/xml", function(error, data) {
                var assetResultsData = d3.select(data).select("AssetResults").selectAll("Result");
                assetResultsData[0].forEach(crunch);
    
                var liabilityResultsDataSol = d3.select(data).selectAll("LiabilityResults Liability[name='Solvency'] Results Item");
                liabilityResultsDataSol[0].forEach(crunch);
    
                var liabilityResultsDataTP = d3.select(data).selectAll("LiabilityResults Liability[name='Technical provisions'] Results Item");
                liabilityResultsDataTP[0].forEach(crunch);
    
                var liabilityResultsDataTV = d3.select(data).selectAll("LiabilityResults Liability[name='Accounting'] Results Item");
                liabilityResultsDataTV[0].forEach(crunch);
    
                x.domain(d3.extent(assetResultsData[0], function (d) { return d.date; }));
                y.domain([450, 600]); //Hard coded for demo purposes
                //y.domain(d3.extent(assetResultsData[0], function (d) { return d.chartValue; }));
                x2.domain(x.domain());
                y2.domain(y.domain());
    
                focus.append("path")
                    .datum(assetResultsData[0])
                    .attr("class", "path_steelblue")
                    .attr("d", line);
    
                focus.append("path")
                    .datum(liabilityResultsDataSol[0])
                    .attr("class", "path_blue")
                    .attr("d", line);
    
                focus.append("path")
                    .datum(liabilityResultsDataTV[0])
                    .attr("class", "path_red")
                    .attr("d", line);
    
                focus.append("path")
                    .datum(liabilityResultsDataTP[0])
                    .attr("class", "path_yellow")
                    .attr("d", line);
    
                focus.append("g")
                    .attr("class", "x axis")
                    .attr("transform", "translate(0," + height + ")")
                    .call(xAxis);
    
                focus.append("g")
                    .attr("class", "y axis")
                    .call(yAxis)
                    .append("text")
                    .attr("transform", "rotate(-90)")
                    .attr("y", 6)
                    .attr("dy", ".71em")
                    .style("text-anchor", "end")
                    .text("Millions ($)");
    
                focus.append("g")
                    .attr("class", "grid")
                    .call(make_y_axis()
                        .tickSize(-width, 0, 0)
                        .tickFormat("")
                    );
    
                context.append("path")
                    .datum(assetResultsData[0])
                    .attr("class", "path_steelblue")
                    .attr("d", line2);
    
                context.append("path")
                    .datum(liabilityResultsDataSol[0])
                    .attr("class", "path_blue")
                    .attr("d", line2);
    
                context.append("path")
                    .datum(liabilityResultsDataTV[0])
                    .attr("class", "path_yellow")
                    .attr("d", line2);
    
                context.append("path")
                    .datum(liabilityResultsDataTP[0])
                    .attr("class", "path_red")
                    .attr("d", line2);
    
                context.append("g")
                    .attr("class", "x axis")
                    .attr("transform", "translate(0," + height2 + ")")
                    .call(xAxis2);
    
                context.append("g")
                    .attr("class", "x brush")
                    .call(brush)
                .selectAll("rect")
                    .attr("y", -6)
                    .attr("height", height2 + 7);
    
                addTooltip(div, assetResultsData[0], "Assets");
                addTooltip(divSolvency, liabilityResultsDataSol[0], "Solvency");
                addTooltip(divTechnical, liabilityResultsDataTV[0], "Technical Provisions");
                addTooltip(divAccounting, liabilityResultsDataTP[0], "Accounting");
            });
    
            // Add mouseover events for hover line.
            d3.select(".tracker-chart").on("mouseover", function() {
                }).on("mousemove", function() {
                        //console.log('mousemove', d3.mouse(this));
                        var mouse_x = d3.mouse(this)[0];
                        var mouse_y = d3.mouse(this)[1];
                        var graph_y = y.invert(mouse_y);
                        var graph_x = x.invert(mouse_x);
                        //console.log(graph_x);
                        var format = d3.time.format('%a %b %d %Y');
                        hoverDate.text(format(graph_x));
                        hoverDate.attr('x', mouse_x);
                        //console.log(x.invert(mouse_x));
                        hoverLine.attr("x1", mouse_x).attr("x2", mouse_x)
                        hoverLine.style("opacity", 1);
                    }).on("mouseout", function() {
                        //hoverLine.style("opacity", 1e-6);
                    });
    
            function addTooltip(div, data, label) {
                focus.selectAll("dot")
                        .data(data)
                    .enter().append("circle")
                        .attr("class", "dot")
                        .attr("r", 5)
                        .attr("cx", function (d) { return x(d.date); })
                        .attr("cy", function (d) { return y(d.chartValue); })
                            .on("mouseover", function(d) {
                                div.transition()
                                    .duration(50)
                                    .style("opacity", .9);
                                div.html(label + "<br />" + formatTime(d.date) + "<br />" + "$" + (d.chartValue).toFixed(3) + " Million")
                                    .style("left", (d3.event.pageX) + "px")
                                    .style("top", (d3.event.pageY - 28) + "px");
    
                        }).on("mouseout", function(d) {
                            div.transition()
                                .duration(200)
                                .style("opacity", 0);
                        });
                        /*
                focus.on('mouseover', function(){
                    brush_elm = focus.select("circle").node();
                    console.log(brush_elm);
                    console.log(this);
                    new_click_event = new Event('mouseover');
                    new_click_event.pageX = d3.event.pageX;
                    new_click_event.clientX = d3.event.clientX;
                    new_click_event.pageY = d3.event.pageY;
                    new_click_event.clientY = d3.event.clientY;
                    brush_elm.dispatchEvent(new_click_event);
                });*/
            }
    
            function brushed() {
                x.domain(brush.empty() ? x2.domain() : brush.extent());
                focus.select(".path_steelblue").attr("d", line);
                focus.select(".path_blue").attr("d", line);
                focus.select(".path_yellow").attr("d", line);
                focus.select(".path_red").attr("d", line);
                focus.select(".x.axis").call(xAxis);
            }
    
            function make_y_axis() {        
                return d3.svg.axis()
                    .scale(y)
                    .orient("left")
                    .ticks(5)
            }
    
            function crunch(d) {
                d.date = parseDate(d.getAttribute("date"));
                d.chartValue = +d.getAttribute("value")/ 1000000;
                d.hoverText = +d.getAttribute("value");
            }
    
  • 如果希望对象跟随鼠标,但不干扰鼠标在基础对象上触发事件的能力,请为其指定样式

  • 如果希望图形元素仅显示在有限的打印区域中,则需要对包含这些元素的组应用属性。您已复制代码以创建
    clipPath
    元素,但从未将其附加到组

  • 我不确定你到底想发生什么,而不是正在发生什么。你能更清楚地解释一下吗,最好是用一个工作示例的链接?您的
    brushed
    函数中没有任何与工具提示相关的内容。至少,您应该选择任何现有工具提示,并根据更新的x比例函数重新定位它们

  • 根据评论进行编辑

    如果您试图对工具提示所做的只是移动它以匹配缩放,那么这相当简单。更改x比例的域后,只需重新设置x坐标:

        function brushed() {
            x.domain(brush.empty() ? x2.domain() : brush.extent());
    
            focus.selectAll("circle.dot") 
                 //or you could just use ".dot" 
                 //but NOT "dot", which you have in your initialization code!
                 .attr("cx", function (d) { return x(d.date); } );
    
            focus.select(".path_steelblue").attr("d", line);
            focus.select(".path_blue").attr("d", line);
            focus.select(".path_yellow").attr("d", line);
            focus.select(".path_red").attr("d", line);
            focus.select(".x.axis").call(xAxis);
        }
    
    顺便说一句,如果您为行提供两个类,一个是所有行的公共类,另一个是每个数据类型的唯一类,那么效率会更高。只需用空格分隔类:

            context.append("path")
                .datum(assetResultsData[0])
                .attr("class", "datapath steelblue")
                .attr("d", line);
    
    然后在CSS中,应用于所有路径的任何属性的选择器将是

    path.datapath {
    }
    

    如果只希望样式应用于主图表中的线条(例如,如果希望主图表中的笔划宽度比小上下文图表中的笔划宽度更宽)

    当然,您仍然可以使用这两个类选择单独的行:

    path.datapath.steelblue {
        stroke: steelblue;
    }
    
    由于d3选择功能使用相同的选择器,在拉丝功能中,您可以使用公共选择器一次性选择所有数据行并更新它们

        function brushed() {
            x.domain(brush.empty() ? x2.domain() : brush.extent());
    
            focus.selectAll("circle.dot") 
                 .attr("cx", function(d) { return x(d.date); } );
    
            focus.selectAll("path.datapath").attr("d", line);
    
            focus.select("g.x.axis").call(xAxis);
        }
    

    是一个函数,它根据每个元素的数据以及创建行函数时指定的x和y比例创建路径信息。

    感谢您的回复。你对问题(1)的回答正是我想要的。我想我知道如何处理问题(2),所以我现在正在研究这个问题。关于问题(3),我使用的是XML数据,其中有很多数据(虽然我可以减少),但我在发布时遇到了困难。因此,很难给出一个有效的例子。我添加了一张图表的图像。重新定位现有的工具提示(参见代码)是我正在尝试做的,只是不确定如何做。谢谢@AmeliaBR工具提示问题现在已经解决,我已经使用了您关于CSS的建议。在“刷牙”时仍然难以包含路径。这些路径似乎包含在焦点小组中,这就是我认为剪辑发生的地方(显然不是)。这也导致了悬停线日期的另一个问题,当添加到
    svg
    元素时,“刷”之后的悬停线日期稍微不同步。(请参见新编辑)如果将日期附加到
    focus
    元素,则日期是同步的,但发际线未与鼠标指针对齐。对于剪切路径,您需要将属性添加到focus
    元素:
    focus.attr(“剪切路径”,“url(#剪辑)”)
    要定位鼠标跟踪线,需要相对于SVG的鼠标坐标,SVG是所定位元素的父元素:
    var mouse_x=d3.mouse(SVG.node())[0]。然后,要从反转的比例中获得正确的值,需要鼠标坐标相对于包含图形的焦点
    元素:
    var graph\u x=x.invert(d3.mouse(focus.node())。再次感谢@AmeliaBR。我需要使用focus.node()来跟踪发际线鼠标。对于剪辑,我使用了
    剪辑路径
    ,而不是
    剪辑路径
    +回答的3个问题中有3个。谢谢
    path.datapath.steelblue {
        stroke: steelblue;
    }
    
        function brushed() {
            x.domain(brush.empty() ? x2.domain() : brush.extent());
    
            focus.selectAll("circle.dot") 
                 .attr("cx", function(d) { return x(d.date); } );
    
            focus.selectAll("path.datapath").attr("d", line);
    
            focus.select("g.x.axis").call(xAxis);
        }