代码之家  ›  专栏  ›  技术社区  ›  Gonçalo Peres

副歌地图上的d3js html工具提示

  •  1
  • Gonçalo Peres  · 技术社区  · 5 年前

    我正在d3.js中构建一个合唱团地图。

    为了方便用户获取信息,我决定添加一个HTML工具提示。

    为此,我定义了一个名为tooptip的变量:

    var tooltip = d3.select("body").append("div")
        .attr("class", "tooltip");
    

    当我绑定数据时,我添加了:

    .on("mouseover", function(d) {
                    tooltip.transition()
                        .duration(200)
                        .style("opacity", .9);
                    tooltip.html("<strong>" + d.properties.average_price_per_pound + "</strong>" + "<br/>" + "Population: " +
                        (d.properties.average_price_per_pound).toLocaleString() + " Million")
                        .style("left", (d3.event.pageX + 5) + "px")
                        .style("top", (d3.event.pageY - 28) + "px");
                })
                .on("mouseout", function(d) {
                    tooltip.transition()
                        .duration(500)
                        .style("opacity", 0);
                })
    

    但它不起作用,如下图所示(注意:当我悬停在一个状态上时,红色会出现)。

    Without the simple tooltip

    我尝试了一种不同的方法,通过添加一个简单的文本工具提示(在我尝试添加HTML工具提示的同一个位置),我可以使它工作,即使我的目标是添加一个HTML工具提示:

    .text(d => d.properties.average_price_per_pound);
    

    With simple tooltip


    考虑到我打算添加一个HTML工具提示,在此过程中的任何帮助都会受到赞赏。

    我要离开贝娄我的 App.JS 因为它可能有帮助。


    App.JS

    //  Define width and height
    var chart_width     =   800;
    var chart_height    =   600;
    
    
    // Define the color scale
    var color           =   d3.scaleQuantize().range([
        "#f7fbff",
        "#deebf7",
        "#c6dbef",
        "#9ecae1",
        "#6baed6",
        "#4292c6",
        "#2171b5",
        "#08519c",
        "#08306b"
    ]);
    
    
    // Navbar
    function openNav() {
        document.getElementById("mySidenav").style.width = "100%";
    }
    
    function closeNav() {
        document.getElementById("mySidenav").style.width = "0";
    }
    
    
    // Define the Tooltip
    var tooltip = d3.select("body").append("div")
        .attr("class", "tooltip");
    
    
    // Define the Map Projection
    var projection      =   d3.geoAlbersUsa()
        .translate([ 0,0 ]);
    var path            =   d3.geoPath( projection );
    
    
    // Create SVG
    var svg             =   d3.select("#chart")
        .append("svg")
        .attr("width", chart_width)
        .attr("height", chart_height);
    
    
    // Zoom
    var zoom_map        =   d3.zoom()
        .scaleExtent([ 0.5, 3.0 ])
        .translateExtent([
            [ -1000, -500 ],
            [ 1000, 500 ]
        ])
        .on( 'zoom', function(){
        // console.log( d3.event );
        var offset      =   [
            d3.event.transform.x,
            d3.event.transform.y
        ];
        var scale       =   d3.event.transform.k * 1100;
    
        projection.translate( offset )
            .scale( scale );
    
        svg.selectAll( 'path' )
            .transition()
            .attr( 'd', path );
    
        svg.selectAll( 'circle' )
            .transition()
            .attr( "cx", function(d) {
                return projection([d.longitude, d.latitude])[0];
            })
            .attr( "cy", function(d) {
                return projection([d.longitude, d.latitude])[1];
            });
    });
    
    var map             =   svg.append( 'g' )
        .attr( 'id', 'map' )
        .call( zoom_map )
        .call(
            zoom_map.transform,
            d3.zoomIdentity
                .translate( chart_width / 2, chart_height / 2 )
                .scale( 1 )
        );
    
    map.append( 'rect' )
        .attr( 'x', 0 )
        .attr( 'y', 0 )
        .attr( 'class', "mapsvg")
        .attr( 'width', chart_width )
        .attr( 'height', chart_height )
        .attr( 'opacity', 0 );
    
    
    // Load Data
    var honeyyear = document.getElementById("vardatayear").value || 2013;
    
    // if(!honeyyear){
    //     honeyyear  = 2013
    // }
    
    // Select what are we analyzing
    // var honeyattribute = document.getElementById('some_input_id').value;
    
    d3.json( `data/HoneyProduction-${honeyyear}.json`, function( honey_data ){
    
        color.domain([
            d3.min( honey_data, function(d){
                return d.average_price_per_pound;
            }),
            d3.max( honey_data, function(d){
                return d.average_price_per_pound;
            })
        ]);
    
        // Load GeoJson Data
        d3.json( 'data/us.json', function( us_data ){
            us_data.features.forEach(function(us_e, us_i){
                honey_data.forEach(function(h_e,h_i){
                    if( us_e.properties.name !== h_e.state ){
                        return null;
                    }
    
                    us_data.features[us_i].properties.average_price_per_pound   =   parseFloat(h_e.average_price_per_pound);
                });
            });
    
    
            // Bind Data
            map.selectAll( 'path' )
                .data( us_data.features )
                .enter()
                .append( 'path' )
                .attr( 'd', path )
                .attr( 'fill', function( d ){
                    var average_price_per_pound         =   d.properties.average_price_per_pound;
                    return average_price_per_pound ? color( average_price_per_pound ) : '#525252';
                })
                .attr( 'stroke', '#fff' )
                .attr( 'stroke-width', 1 )
                .append('title')
                // .text(d => console.log(d))
                .on("mouseover", function(d) {
                    tooltip.transition()
                        .duration(200)
                        .style("opacity", .9);
                    tooltip.html("<strong>" + d.properties.average_price_per_pound + "</strong>" + "<br/>" + "Population: " +
                        (d.properties.average_price_per_pound).toLocaleString() + " Million")
                        .style("left", (d3.event.pageX + 5) + "px")
                        .style("top", (d3.event.pageY - 28) + "px");
                })
                .on("mouseout", function(d) {
                    tooltip.transition()
                        .duration(500)
                        .style("opacity", 0);
                })
                // // For the simple tooltip
                // .text(d => d.properties.average_price_per_pound);
    
        });
    
    
    
        // Legend
        const x = d3.scaleLinear()
            .domain(d3.extent(color.domain()))
            .rangeRound([500, 750]);
    
        const g = svg.append("g")
            .attr( "class", "legend" )
            .attr("transform", "translate(0,40)");
    
        g.selectAll("rect")
            .data(color.range().map(d => color.invertExtent(d)))
            .enter().append("rect")
            .attr("height", 8)
            .attr("x", d => x(d[0]))
            .attr("width", d => x(d[1]) - x(d[0]))
            .attr("fill", d => color(d[0]));
    
        g.append("text")
            .attr("class", "caption")
            .attr("x", x.range()[0])
            .attr("y", -6)
            .attr("fill", "#fff")
            .attr("text-anchor", "start")
            .attr("font-weight", "bold")
            .text('Average Price per Pound (cents)');
    
        g.call(d3.axisBottom(x)
            .tickSize(13)
            .tickFormat(( honey_data, function(d){
                return d.average_price_per_pound;
            }),)
            .tickValues(color.range().slice(1).map(d => color.invertExtent(d)[0])))
            .select(".domain")
            .remove();
    
        // svg.append("g")
        //     .selectAll("path")
        //     .data(honey_data, function(d){
        //         return d.average_price_per_pound;
        //     })
        //     .enter().append("path")
        //     .attr("fill", d => color(d.average_price_per_pound))
        //     .attr("d", path)
        //     .append("title")
        //     .text(d => (d.average_price_per_pound));
        //
        // svg.append("path")
        //     .datum(honey_data, function(d){
        //         return d.average_price_per_pound;
        //     })
        //     .attr("fill", "none")
        //     .attr("stroke", "white")
        //     .attr("stroke-linejoin", "round")
        //     .attr("d", path);
    
    
    });
    
    // Panning
    d3.selectAll( '#buttons button.panning' ).on( 'click', function(){
        var x           =   0;
        var y           =   0;
        var distance    =   100;
        var direction   =   d3.select( this ).attr( 'class' ).replace( 'panning ', '' );
    
        if( direction === "up" ){
            y           +=  distance; // Increase y offset
        }else if( direction === "down" ){
            y           -=  distance; // Decrease y offset
        }else if( direction === "left" ){
            x           +=  distance; // Increase x offset
        }else if( direction === "right" ){
            x           -=  distance; // Decrease x offset
        }
    
        map.transition()
            .call( zoom_map.translateBy, x, y );
    });
    
    
    // Zooming
    d3.selectAll( '#buttons button.zooming' ).on( 'click', function(){
        var scale       =   1;
        var direction   =   d3.select(this).attr("class").replace( 'zooming ', '' );
    
        if( direction === "in" ){
            scale       =  1.25;
        }else if(direction === "out"){
            scale       =  0.75;
        }
    
        map.transition()
            .call(zoom_map.scaleBy, scale);
    });
    
    
    // Slider
    function update(year){
         slider.property("value", year);
         d3.select(".year").text(year);
         // honeyyear.style("fill", function(d) {
         //      return color(d.properties.years[year][0].rate)
         };
    
    
    var slider = d3.select(".slider")
        .append("input")
        .attr("type", "range")
        .attr("min", 2009)
        .attr("max", 2013)
        .attr("step", 1)
        .on("input", function() {
             var year = this.value;
             update(year);
         });
    
    update(2013);
    
    1 回复  |  直到 5 年前
        1
  •  1
  •   ksav    5 年前

    问题是,当您 append('title') ,所以您基本上是在一个空的SVG中添加一个mouseover事件侦听器。 <title> 标记,它是您实际要将事件处理程序附加到的路径的子级。

    您仍然可以在此链中附加标题,只要这样做。 之后 附加事件处理程序。

    请参阅以下并排示例:

    此工作-事件处理程序附加到所需元素

    var tooltip = d3
      .select("body")
      .append("div")
      .attr("class", "tooltip");
    
    const sampleData = [
      {
        properties: {
          average_price_per_pound: 5000
        }
      },
      {
        properties: {
          average_price_per_pound: 15000
        }
      },
      {
        properties: {
          average_price_per_pound: 555000
        }
      }
    ];
    
    d3
      .select("body")
      .selectAll(".item")
      .data(sampleData)
      .enter()
      .append("div")
      .classed("item", true)
      .html(d => {
        return d.properties.average_price_per_pound;
      })
      .on("mouseover", function(d) {
        tooltip.html(
          `<strong>${
            d.properties.average_price_per_pound
          }</strong><br/>Population: ${d.properties.average_price_per_pound.toLocaleString()} Million`
        );
      });
    .tooltip {
      position: absolute;
      background: white;
      border: 2px solid black;
      left: 100px;
      padding: 5px;
      border-radius: 5px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

    不起作用-事件处理程序附加到不需要的空子元素

    var tooltip = d3
      .select("body")
      .append("div")
      .attr("class", "tooltip");
    
    const sampleData = [
      {
        properties: {
          average_price_per_pound: 5000
        }
      },
      {
        properties: {
          average_price_per_pound: 15000
        }
      },
      {
        properties: {
          average_price_per_pound: 555000
        }
      }
    ];
    
    d3
      .select("body")
      .selectAll(".item")
      .data(sampleData)
      .enter()
      .append("div")
      .classed("item", true)
      .html(d => {
        return d.properties.average_price_per_pound;
      })
      .append('span')
      .on("mouseover", function(d) {
        tooltip.html(
          `<strong>${
            d.properties.average_price_per_pound
          }</strong><br/>Population: ${d.properties.average_price_per_pound.toLocaleString()} Million`
        );
      });
    工具提示{
    位置:绝对;
    背景:白色;
    边框:2倍纯黑;
    左:100px;
    填料:5px;
    边界半径:5px;
    }
    <script src=“https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js”></script>