代码之家  ›  专栏  ›  技术社区  ›  Aenaon

d3.js沃罗诺事件。当光标正好位于点上方时,鼠标悬停似乎会消失

  •  0
  • Aenaon  · 技术社区  · 6 年前

    请问我在这里做错了什么?当鼠标进入相关的voronoi单元格时,我想增加点的大小,但是当鼠标位于该点上方时,该点会回到其原始大小;我已经尝试了 mouseover mousemove 没有运气的事情。代码片段,你可以放大,你将能够看到我刚才描述的。 非常感谢!

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
    <meta charset="utf-8">
    
    <title>Chart</title>
    
    
    <!-- Reference minified version of D3 -->
    <script src='https://d3js.org/d3.v4.min.js' type='text/javascript'></script>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js'></script>
    </head>
    
    <body>
        <style>
            .grid line {
                stroke: #ddd;
            }
        </style>
    
    
    <div id='scatter-plot'>
    <svg width="700" height="500">
    </svg>
    </div>
    
       
    <script>
    
                var data = [];
                    for (let i = 0; i < 200; i++) {
                    data.push({
                        x: Math.random(),
                        y: Math.random(),
                        dotNum: i,
                    })
                }
                    
            renderChart(data)
     
        
    
            
    function renderChart(data) {
    
        var totalWidth = 920,
            totalHeight = 480;
        
        var margin = {
                top: 10,
                left: 50,
                bottom: 30,
                right: 0
            }
        
        var width = totalWidth  - margin.left - margin.right,
            height = totalHeight  - margin.top - margin.bottom;
    
        // inner chart dimensions, where the dots are plotted
    //    var width = width - margin.left - margin.right;
    //    var height = height - margin.top - margin.bottom;
        
         var tsn = d3.transition().duration(200);
    
        // radius of points in the scatterplot
        var pointRadius = 2;
    
        var extent = {
            x: d3.extent(data, function (d) {return d.x}),
            y: d3.extent(data, function (d) {return d.y}),
        };
    
        var scale = {
            x: d3.scaleLinear().range([0, width]),
            y: d3.scaleLinear().range([height, 0]),
        };
    
        var axis = {
            x: d3.axisBottom(scale.x).ticks(xTicks).tickSizeOuter(0),
            y: d3.axisLeft(scale.y).ticks(yTicks).tickSizeOuter(0),
        };
        
        var gridlines = {
            x: d3.axisBottom(scale.x).tickFormat("").tickSize(height),
            y: d3.axisLeft(scale.y).tickFormat("").tickSize(-width),
        }
        
    
        var colorScale = d3.scaleLinear().domain([0, 1]).range(['#06a', '#06a']);
    
        // select the root container where the chart will be added
        var container = d3.select('#scatter-plot');
    
        var zoom = d3.zoom()
            .scaleExtent([1, 20])
            .on("zoom", zoomed);
        
        var tooltip = d3.select("body").append("div")
            .attr("id", "tooltip")
            .style("opacity", 0);
    
        // initialize main SVG
        var svg = container.select('svg')
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .call(zoom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
        
        // Clip path
        svg.append("clipPath")
            .attr("id", "clip")
            .append("rect")
            .attr("width", width)
            .attr("height", height);
    
    
        // Heatmap dots
        var dotsGroup = svg.append("g")
            .attr("clip-path", "url(#clip)")
            .append("g");
        
        //Create X axis
        var renderXAxis = svg.append("g")
            .attr("class", "x axis")
    
        //Create Y axis
        var renderYAxis = svg.append("g")
            .attr("class", "y axis")
    
    
        // set up axis generating functions
        var xTicks = Math.round(width / 50);
        var yTicks = Math.round(height / 50);
    
        
        function updateScales(data, scale){
            scale.x.domain([extent.x[0], extent.x[1]]).nice(),
            scale.y.domain([extent.y[0], extent.y[1]]).nice()
        }
    
        function zoomed() {
            d3.event.transform.x = d3.event.transform.x;
            d3.event.transform.y = d3.event.transform.y;
    
            // update: rescale x axis
            renderXAxis.call(axis.x.scale(d3.event.transform.rescaleX(scale.x)));
            renderYAxis.call(axis.y.scale(d3.event.transform.rescaleX(scale.y)));
    
    
            dotsGroup.attr("transform", d3.event.transform);
        }
        
        // add the overlay on top of everything to take the mouse events
        dotsGroup.append('rect')
            .attr('class', 'overlay')
            .attr('width', width)
            .attr('height', height)
            .style('fill', 'red')
            .style('opacity', 0)
            .on('mouseover', mouseMoveHandler)
            .on('mouseleave', () => {
                // hide the highlight circle when the mouse leaves the chart
                highlight(null);
        });
        
        renderPlot(data);
        
        function renderPlot(data){
            updateScales(data, scale);
            
            svg.select('.y.axis')
                .attr("transform", "translate(" + -pointRadius + " 0)" )
                .call(axis.y);
            
            var h = height + pointRadius;
            svg.select('.x.axis')
                .attr("transform", "translate(0, " + h + ")")
                .call(axis.x);
            
            svg.append("g")
                .attr("class", "grid")
                .call(gridlines.x);
            
            svg.append("g")
                .attr("class", "grid")
                .call(gridlines.y);
            
            
            //Do the chart
            var update = dotsGroup.selectAll("circle").data(data)
            
            update
                .enter()
                .append('circle')
                .attr('r', pointRadius)
                .attr('cx', d => scale.x(d.x))
                .attr('cy', d => scale.y(d.y))
                .attr('fill', d => colorScale(d.y))
        };
    
    
        // create a voronoi diagram 
        var voronoiDiagram = d3.voronoi()
            .x(d => scale.x(d.x))
            .y(d => scale.y(d.y))
            .size([width, height])(data);
    
    
        // add a circle for indicating the highlighted point
        dotsGroup.append('circle')
            .attr('class', 'highlight-circle')
            .attr('r', pointRadius*2) // increase the size if highlighted
            .style('fill', 'red')
            .style('display', 'none');
    
        // callback to highlight a point
        function highlight(d) {
            // no point to highlight - hide the circle and the tooltip
            if (!d) {
                d3.select('.highlight-circle').style('display', 'none');
                //tooltip.style("opacity",0);
                // otherwise, show the highlight circle at the correct position
            } else {
                d3.select('.highlight-circle')
                    .style('display', '')
                    .style('stroke', colorScale(d.y))
                    .attr('cx', scale.x(d.x))
                    .attr('cy', scale.y(d.y));
            }
        }
    
        // callback for when the mouse moves across the overlay
        function mouseMoveHandler() {
            // get the current mouse position
            var [mx, my] = d3.mouse(this);
    
            var site = voronoiDiagram.find(mx, my);
    
            // highlight the point if we found one, otherwise hide the highlight circle
            highlight(site && site.data);
    
    
            for (let i = 0; i < site.data.dotNum; i++) {
                //do something....
            }
            
        }
    
    
    
    
    }
    
    
    
        
    </script>
    </body>
    
    </html>
    1 回复  |  直到 6 年前
        1
  •  1
  •   rioV8    6 年前
    • 你必须画出 overlay 在圆和高光圆之后的矩形。如果没有,则将鼠标悬停在一个圆上会生成一个鼠标离开事件,并且您会看到突出显示圆的闪烁
    • 使用 mousemove 事件不是 mouseover ,这是一种 鼠标进入 事件
    • 我添加了逻辑,只在亮点变点时更新
    • 缩放和平移时网格未更新(未固定)
    • 即使是在 覆盖 仍然有 mouseleave 事件-它们是由网格线引起的。在网格线组之后移动点组

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
    <meta charset="utf-8">
    
    <title>Chart</title>
    
    
    <!-- Reference minified version of D3 -->
    <script src='https://d3js.org/d3.v4.min.js' type='text/javascript'></script>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js'></script>
    </head>
    
    <body>
    <style>
    .grid line { stroke: #ddd; }
    </style>
    
    <div id='scatter-plot'>
    <svg width="700" height="500">
    </svg>
    </div>
    
    <script>
    
    var data = [];
        for (let i = 0; i < 200; i++) {
        data.push({
            x: Math.random(),
            y: Math.random(),
            dotNum: i,
        })
    }
    renderChart(data);
    
    function renderChart(data) {
    
        var totalWidth = 920,
            totalHeight = 480;
    
        var margin = {
                top: 10,
                left: 50,
                bottom: 30,
                right: 0
            }
    
        var width = totalWidth  - margin.left - margin.right,
            height = totalHeight  - margin.top - margin.bottom;
    
        // inner chart dimensions, where the dots are plotted
    //    var width = width - margin.left - margin.right;
    //    var height = height - margin.top - margin.bottom;
    
         var tsn = d3.transition().duration(200);
    
        // radius of points in the scatterplot
        var pointRadius = 2;
    
        var extent = {
            x: d3.extent(data, function (d) {return d.x}),
            y: d3.extent(data, function (d) {return d.y}),
        };
    
        var scale = {
            x: d3.scaleLinear().range([0, width]),
            y: d3.scaleLinear().range([height, 0]),
        };
    
        var axis = {
            x: d3.axisBottom(scale.x).ticks(xTicks).tickSizeOuter(0),
            y: d3.axisLeft(scale.y).ticks(yTicks).tickSizeOuter(0),
        };
        
        var gridlines = {
            x: d3.axisBottom(scale.x).tickFormat("").tickSize(height),
            y: d3.axisLeft(scale.y).tickFormat("").tickSize(-width),
        }
    
        var colorScale = d3.scaleLinear().domain([0, 1]).range(['#06a', '#06a']);
    
        // select the root container where the chart will be added
        var container = d3.select('#scatter-plot');
    
        var zoom = d3.zoom()
            .scaleExtent([1, 20])
            .on("zoom", zoomed);
    
        var tooltip = d3.select("body").append("div")
            .attr("id", "tooltip")
            .style("opacity", 0);
    
        // initialize main SVG
        var svg = container.select('svg')
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .call(zoom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
        // Clip path
        svg.append("clipPath")
            .attr("id", "clip")
            .append("rect")
            .attr("width", width)
            .attr("height", height);
    
        //Create X axis
        var renderXAxis = svg.append("g")
            .attr("class", "x axis")
    
        //Create Y axis
        var renderYAxis = svg.append("g")
            .attr("class", "y axis")
    
        // set up axis generating functions
        var xTicks = Math.round(width / 50);
        var yTicks = Math.round(height / 50);
    
        function updateScales(data, scale){
            scale.x.domain([extent.x[0], extent.x[1]]).nice(),
            scale.y.domain([extent.y[0], extent.y[1]]).nice()
        }
    
        function zoomed() {
            d3.event.transform.x = d3.event.transform.x;
            d3.event.transform.y = d3.event.transform.y;
    
            // update: rescale x axis
            renderXAxis.call(axis.x.scale(d3.event.transform.rescaleX(scale.x)));
            renderYAxis.call(axis.y.scale(d3.event.transform.rescaleX(scale.y)));
    
            dotsGroup.attr("transform", d3.event.transform);
        }
    
        var dotsGroup;
        renderPlot(data);
    
        function renderPlot(data){
            updateScales(data, scale);
            
            svg.select('.y.axis')
                .attr("transform", "translate(" + -pointRadius + " 0)" )
                .call(axis.y);
            
            var h = height + pointRadius;
            svg.select('.x.axis')
                .attr("transform", "translate(0, " + h + ")")
                .call(axis.x);
            
            svg.append("g")
                .attr("class", "grid")
                .call(gridlines.x);
            
            svg.append("g")
                .attr("class", "grid")
                .call(gridlines.y);
    
            dotsGroup = svg.append("g")
                           .attr("clip-path", "url(#clip)")
                           .append("g");
            
            //Do the chart
            var update = dotsGroup.selectAll("circle").data(data)
            
            update
                .enter()
                .append('circle')
                .attr('r', pointRadius)
                .attr('cx', d => scale.x(d.x))
                .attr('cy', d => scale.y(d.y))
                .attr('fill', d => colorScale(d.y))
        };
    
        // create a voronoi diagram 
        var voronoiDiagram = d3.voronoi()
            .x(d => scale.x(d.x))
            .y(d => scale.y(d.y))
            .size([width, height])(data);
    
        // add a circle for indicating the highlighted point
        dotsGroup.append('circle')
            .attr('class', 'highlight-circle')
            .attr('r', pointRadius*2) // increase the size if highlighted
            .style('fill', 'red')
            .style('display', 'none');
    
        // add the overlay on top of everything to take the mouse events
        dotsGroup.append('rect')
            .attr('class', 'overlay')
            .attr('width', width)
            .attr('height', height)
            .style('fill', 'red')
            .style('opacity', 0)
            .on('mousemove', mouseMoveHandler)
            .on('mouseleave', () => {
                // hide the highlight circle when the mouse leaves the chart
                console.log('mouse leave');
                highlight(null);
        });
    
        var prevHighlightDotNum = null;
        // callback to highlight a point
        function highlight(d) {
            // no point to highlight - hide the circle and the tooltip
            if (!d) {
                d3.select('.highlight-circle').style('display', 'none');
                prevHighlightDotNum = null;
                //tooltip.style("opacity",0);
                // otherwise, show the highlight circle at the correct position
            } else {
                if (prevHighlightDotNum !== d.dotNum) {
                    d3.select('.highlight-circle')
                      .style('display', '')
                      .style('stroke', colorScale(d.y))
                      .attr('cx', scale.x(d.x))
                      .attr('cy', scale.y(d.y));
                    prevHighlightDotNum = d.dotNum;
                }
            }
        }
    
        // callback for when the mouse moves across the overlay
        function mouseMoveHandler() {
            // get the current mouse position
            var [mx, my] = d3.mouse(this);
    
            var site = voronoiDiagram.find(mx, my);
    
            //console.log('site', site);
            // highlight the point if we found one, otherwise hide the highlight circle
            highlight(site && site.data);
    
            for (let i = 0; i < site.data.dotNum; i++) {
                //do something....
            }
        }
    }
    </script>
    </body>
    
    </html>
    推荐文章