色度图上的D3js HTML工具提示

时间:2019-01-23 11:23:30

标签: javascript d3.js

我正在D3.js中构建一个Choropleth地图。

为了使用户更容易理解信息,我决定添加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 个答案:

答案 0 :(得分:1)

问题在于,append('title')丢失了对路径的选择,因此,您基本上是将一个鼠标悬停事件监听器添加到一个空的svg <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`
    );
  });
.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>