如何在d3中的鼠标悬停上显示多个值?

时间:2018-05-11 16:45:11

标签: javascript dictionary d3.js mouseover

我希望将鼠标悬停在地图上的国家/地区时显示多个值(价格,点数)。例如,当我将鼠标悬停在英国时,我希望同时看到平均价格和积分。但我只能用d.properties.name显示其中一个。 代码取自here.

我对代码的更改:



<!DOCTYPE html>
<meta charset="utf-8">
<style>

body {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  width: 960px;
  height: 500px;
  position: relative;
}

#canvas {
}

#canvas-svg {
}


.land {
  fill: #222;
}

.boundary {
  fill: none;
  stroke: #fff;
  stroke-width: 1px;
}

#tooltip-container {
  position: absolute;
  background-color: #fff;
  color: #000;
  padding: 10px;
  border: 1px solid;
  display: none;
}

.tooltip_key {
  font-weight: bold;
}

.tooltip_value {
  margin-left: 20px;
  float: right;
}

</style>

<div id="tooltip-container"></div>

<div id="canvas-svg"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/topojson/1.1.0/topojson.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>

<script>

    
d3.csv("MyData130.csv", function(err, data) {

  var config = {"data0":"country","data1":"price", "data2": "points",
              "label0":"label 0","label1":"label 1","label2":"label 2", "color0":"#99ccff","color1":"#0050A1", "color3":"#4398ef",
              "width":900,"height":900}
  
  var width = config.width,
      height = config.height;
  
  var COLOR_COUNTS = 9;
  
  function Interpolate(start, end, steps, count) {
      var s = start,
          e = end,
          final = s + (((e - s) / steps) * count);
      return Math.floor(final);
  }
  
  function Color(_r, _g, _b) {
      var r, g, b;
      var setColors = function(_r, _g, _b) {
          r = _r;
          g = _g;
          b = _b;
      };
  
      setColors(_r, _g, _b);
      this.getColors = function() {
          var colors = {
              r: r,
              g: g,
              b: b
          };
          return colors;
      };
  }
  
  function hexToRgb(hex) {
      var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
      return result ? {
          r: parseInt(result[1], 16),
          g: parseInt(result[2], 16),
          b: parseInt(result[3], 16)
      } : null;
  }
  
  function valueFormat(d) {
    if (d > 1000000000) {
      return Math.round(d / 1000000000 * 10) / 10 + "B";
    } else if (d > 1000000) {
      return Math.round(d / 1000000 * 10) / 10 + "M";
    } else if (d > 1000) {
      return Math.round(d / 1000 * 10) / 10 + "K";
    } else {
      return d;
    }
  }
  
  var COLOR_FIRST = config.color0, COLOR_LAST = config.color1;
  
  var rgb = hexToRgb(COLOR_FIRST);
  
  var COLOR_START = new Color(rgb.r, rgb.g, rgb.b);
  
  rgb = hexToRgb(COLOR_LAST);
  var COLOR_END = new Color(rgb.r, rgb.g, rgb.b);
  
  var startColors = COLOR_START.getColors(),
      endColors = COLOR_END.getColors();
  
  var colors = [];
  
  for (var i = 0; i < COLOR_COUNTS; i++) {
    var r = Interpolate(startColors.r, endColors.r, COLOR_COUNTS, i);
    var g = Interpolate(startColors.g, endColors.g, COLOR_COUNTS, i);
    var b = Interpolate(startColors.b, endColors.b, COLOR_COUNTS, i);
    colors.push(new Color(r, g, b));
  }
  
  var MAP_KEY = config.data0;
  var MAP_VALUE = config.data1;
    
    var MAP_KEY2 = config.data0;
    var MAP_VALUE2 = config.data2;
  
  var projection = d3.geo.mercator()
      .scale((width + 1) / 2 / Math.PI)
      .translate([width / 2, height / 2])
      .precision(.1);
  
  var path = d3.geo.path()
      .projection(projection);
  
  var graticule = d3.geo.graticule();
  
  var svg = d3.select("#canvas-svg").append("svg")
      .attr("width", width)
      .attr("height", height);
  
  svg.append("path")
      .datum(graticule)
      .attr("class", "graticule")
      .attr("d", path);
  
  var valueHash = {};
  
  function log10(val) {
    return Math.log(val);
  }
  
  data.forEach(function(d) {
    valueHash[d[MAP_KEY]] = +d[MAP_VALUE];
    valueHash[d[MAP_KEY2]] = +d[MAP_VALUE2];
  });
  
    
  var quantize = d3.scale.quantize()
      .domain([0, 1.0])
      .range(d3.range(COLOR_COUNTS).map(function(i) { return i }));
  
  quantize.domain([d3.min(data, function(d){
      return (+d[MAP_VALUE], +d[MAP_VALUE2]) }),
    d3.max(data, function(d){
      return (+d[MAP_VALUE], +d[MAP_VALUE2])})]);
  
  d3.json("https://s3-us-west-2.amazonaws.com/vida-public/geo/world-topo-min.json", function(error, world) {
    var countries = topojson.feature(world, world.objects.countries).features;
  
    svg.append("path")
       .datum(graticule)
       .attr("class", "choropleth")
       .attr("d", path);
  
    var g = svg.append("g");
  
    g.append("path")
     .datum({type: "LineString", coordinates: [[-180, 0], [-90, 0], [0, 0], [90, 0], [180, 0]]})
     .attr("class", "equator")
     .attr("d", path);
  
    var country = g.selectAll(".country").data(countries);
  
    country.enter().insert("path")
        .attr("class", "country")
        .attr("d", path)
        .attr("id", function(d,i) { return d.id; })
        .attr("title", function(d) { return d.properties.name; })
        .style("fill", function(d) {
          if ((valueHash[d.properties.name])) {
              valueHash[d.properties.value] = valueHash[d[MAP_KEY2]];
            var c = quantize((valueHash[d.properties.name]) );
            var color = colors[c].getColors();
            return "rgb(" + color.r + "," + color.g +
                "," + color.b + ")";
          } else {
            return "#ccc";
          }
        })
        .on("mousemove", function(d) {
            var html = "";
  
            html += "<div class=\"tooltip_kv\">";
            html += "<span class=\"tooltip_key\">";
            html += d.properties.name + "<br/>";
//            html += d.properties.value;   
            html += "</span>";
            html += "<span class=\"tooltip_value\">";
            html += (valueHash[d.properties.name] ? "Average Price: " + valueFormat(valueHash[d.properties.name]) +" $"+ 
                     "<br/>" + "Average Points: " + valueFormat(valueHash[d.properties.value]) : "");
            html += "";
            html += "</span>";
            html += "</div>";
            
            $("#tooltip-container").html(html);
            $(this).attr("fill-opacity", "0.8");
            $("#tooltip-container").show();
            
            var coordinates = d3.mouse(this);
            
            var map_width = $('.choropleth')[0].getBoundingClientRect().width;
            
            if (d3.event.pageX < map_width / 2) {
              d3.select("#tooltip-container")
                .style("top", (d3.event.layerY + 15) + "px")
                .style("left", (d3.event.layerX + 15) + "px");
            } else {
              var tooltip_width = $("#tooltip-container").width();
              d3.select("#tooltip-container")
                .style("top", (d3.event.layerY + 15) + "px")
                .style("left", (d3.event.layerX - tooltip_width - 30) + "px");
            }
        })
        .on("mouseout", function() {
                $(this).attr("fill-opacity", "1.0");
                $("#tooltip-container").hide();
            });
    
    g.append("path")
        .datum(topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; }))
        .attr("class", "boundary")
        .attr("d", path);
    
    svg.attr("height", config.height * 2.2 / 3);
  });
  
  d3.select(self.frameElement).style("height", (height * 2.3 / 3) + "px");
});
    
    


</script>
&#13;
&#13;
&#13;

CSV文件:

&#13;
&#13;
	country	price	points
1	Azerbaijan	24.59322034	88.63492063
2	Argentina	24.51011715	86.71026316
3	Armenia	14.5	87.5
4	Australia	35.43766347	88.58050666
5	Austria	30.76277242	90.10134529
6	Bosnia and Herzegovina	12.5	86.5
7	Brazil	23.76595745	84.67307692
8	Bulgaria	14.64539007	87.93617021
9	Canada	35.71259843	89.36964981
10	Chile	20.78645833	86.49351521
&#13;
&#13;
&#13;

我非常愿意自己实施,但我不知道如何做到这一点。我用Google搜索了很多次,但找不到任何有用的东西。也许有人有想法或给我一些提示,所以我可以做得对。

1 个答案:

答案 0 :(得分:1)

几个问题:

  • tsv被解析为csv
  • 您正在覆盖价格点(MAP_KEY和MAP_KEY2都是'国家'):
valueHash[d[MAP_KEY]] = +d[MAP_VALUE];
valueHash[d[MAP_KEY2]] = +d[MAP_VALUE2];

我在价格和点数上使用了不同的哈希值,但我建议您使用更好的数据结构来保存两者。这是更正后的代码:

<!DOCTYPE html>
<meta charset="utf-8">
<style>

    body {
        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
        width: 960px;
        height: 500px;
        position: relative;
    }

    #canvas {
    }

    #canvas-svg {
    }


    .land {
        fill: #222;
    }

    .boundary {
        fill: none;
        stroke: #fff;
        stroke-width: 1px;
    }

    #tooltip-container {
        position: absolute;
        background-color: #fff;
        color: #000;
        padding: 10px;
        border: 1px solid;
        display: none;
    }

    .tooltip_key {
        font-weight: bold;
    }

    .tooltip_value {
        margin-left: 20px;
        float: right;
    }

</style>

<div id="tooltip-container"></div>

<div id="canvas-svg"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/topojson/1.1.0/topojson.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>

<script>


    d3.tsv("dat.tsv", function(err, data) {

        var config = {"data0":"country","data1":"price", "data2": "points",
            "label0":"label 0","label1":"label 1","label2":"label 2", "color0":"#99ccff","color1":"#0050A1", "color3":"#4398ef",
            "width":900,"height":900}

        var width = config.width,
                height = config.height;

        var COLOR_COUNTS = 9;

        function Interpolate(start, end, steps, count) {
            var s = start,
                    e = end,
                    final = s + (((e - s) / steps) * count);
            return Math.floor(final);
        }

        function Color(_r, _g, _b) {
            var r, g, b;
            var setColors = function(_r, _g, _b) {
                r = _r;
                g = _g;
                b = _b;
            };

            setColors(_r, _g, _b);
            this.getColors = function() {
                var colors = {
                    r: r,
                    g: g,
                    b: b
                };
                return colors;
            };
        }

        function hexToRgb(hex) {
            var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
            return result ? {
                r: parseInt(result[1], 16),
                g: parseInt(result[2], 16),
                b: parseInt(result[3], 16)
            } : null;
        }

        function valueFormat(d) {
            if (d > 1000000000) {
                return Math.round(d / 1000000000 * 10) / 10 + "B";
            } else if (d > 1000000) {
                return Math.round(d / 1000000 * 10) / 10 + "M";
            } else if (d > 1000) {
                return Math.round(d / 1000 * 10) / 10 + "K";
            } else {
                return d;
            }
        }

        var COLOR_FIRST = config.color0, COLOR_LAST = config.color1;

        var rgb = hexToRgb(COLOR_FIRST);

        var COLOR_START = new Color(rgb.r, rgb.g, rgb.b);

        rgb = hexToRgb(COLOR_LAST);
        var COLOR_END = new Color(rgb.r, rgb.g, rgb.b);

        var startColors = COLOR_START.getColors(),
                endColors = COLOR_END.getColors();

        var colors = [];

        for (var i = 0; i < COLOR_COUNTS; i++) {
            var r = Interpolate(startColors.r, endColors.r, COLOR_COUNTS, i);
            var g = Interpolate(startColors.g, endColors.g, COLOR_COUNTS, i);
            var b = Interpolate(startColors.b, endColors.b, COLOR_COUNTS, i);
            colors.push(new Color(r, g, b));
        }

        var MAP_KEY = config.data0;
        var MAP_VALUE = config.data1;

        var MAP_KEY2 = config.data0;
        var MAP_VALUE2 = config.data2;

        var projection = d3.geo.mercator()
                .scale((width + 1) / 2 / Math.PI)
                .translate([width / 2, height / 2])
                .precision(.1);

        var path = d3.geo.path()
                .projection(projection);

        var graticule = d3.geo.graticule();

        var svg = d3.select("#canvas-svg").append("svg")
                .attr("width", width)
                .attr("height", height);

        svg.append("path")
                .datum(graticule)
                .attr("class", "graticule")
                .attr("d", path);

        var valueHash = {};

        function log10(val) {
            return Math.log(val);
        }

        data.forEach(function(d) {
            valueHash[d[MAP_KEY]] = +d[MAP_VALUE];
        });

        var pointsHash = {};

        data.forEach(function(d) {
            pointsHash[d[MAP_KEY2]] = +d[MAP_VALUE2];
        });

        var quantize = d3.scale.quantize()
                .domain([0, 1.0])
                .range(d3.range(COLOR_COUNTS).map(function(i) { return i }));

        quantize.domain([d3.min(data, function(d){
            return (+d[MAP_VALUE], +d[MAP_VALUE2]) }),
            d3.max(data, function(d){
                return (+d[MAP_VALUE], +d[MAP_VALUE2])})]);

        d3.json("https://s3-us-west-2.amazonaws.com/vida-public/geo/world-topo-min.json", function(error, world) {
            var countries = topojson.feature(world, world.objects.countries).features;

            svg.append("path")
                    .datum(graticule)
                    .attr("class", "choropleth")
                    .attr("d", path);

            var g = svg.append("g");

            g.append("path")
                    .datum({type: "LineString", coordinates: [[-180, 0], [-90, 0], [0, 0], [90, 0], [180, 0]]})
                    .attr("class", "equator")
                    .attr("d", path);

            var country = g.selectAll(".country").data(countries);

            country.enter().insert("path")
                    .attr("class", "country")
                    .attr("d", path)
                    .attr("id", function(d,i) { return d.id; })
                    .attr("title", function(d) { return d.properties.name; })
                    .style("fill", function(d) {
                        if ((valueHash[d.properties.name])) {
                            valueHash[d.properties.value] = valueHash[d[MAP_KEY2]];
                            var c = quantize((valueHash[d.properties.name]) );
                            var color = colors[c].getColors();
                            return "rgb(" + color.r + "," + color.g +
                                    "," + color.b + ")";
                        } else {
                            return "#ccc";
                        }
                    })
                    .on("mousemove", function(d) {
                        debugger;
                        var html = "";

                        html += "<div class=\"tooltip_kv\">";
                        html += "<span class=\"tooltip_key\">";
                        html += d.properties.name + "<br/>";
//            html += d.properties.value;
                        html += "</span>";
                        html += "<span class=\"tooltip_value\">";
                        html += (valueHash[d.properties.name] ? "Average Price: " + valueFormat(valueHash[d.properties.name]) +" $"+
                        "<br/>" + "Average Points: " + valueFormat(pointsHash[d.properties.name]) : "");
                        html += "";
                        html += "</span>";
                        html += "</div>";

                        $("#tooltip-container").html(html);
                        $(this).attr("fill-opacity", "0.8");
                        $("#tooltip-container").show();

                        var coordinates = d3.mouse(this);

                        var map_width = $('.choropleth')[0].getBoundingClientRect().width;

                        if (d3.event.pageX < map_width / 2) {
                            d3.select("#tooltip-container")
                                    .style("top", (d3.event.layerY + 15) + "px")
                                    .style("left", (d3.event.layerX + 15) + "px");
                        } else {
                            var tooltip_width = $("#tooltip-container").width();
                            d3.select("#tooltip-container")
                                    .style("top", (d3.event.layerY + 15) + "px")
                                    .style("left", (d3.event.layerX - tooltip_width - 30) + "px");
                        }
                    })
                    .on("mouseout", function() {
                        $(this).attr("fill-opacity", "1.0");
                        $("#tooltip-container").hide();
                    });

            g.append("path")
                    .datum(topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; }))
                    .attr("class", "boundary")
                    .attr("d", path);

            svg.attr("height", config.height * 2.2 / 3);
        });

        d3.select(self.frameElement).style("height", (height * 2.3 / 3) + "px");
    });




</script>

no	country	price	points
1	Azerbaijan	24.59322034	88.63492063
2	Argentina	24.51011715	86.71026316
3	Armenia	14.5	87.5
4	Australia	35.43766347	88.58050666
5	Austria	30.76277242	90.10134529
6	Bosnia and Herzegovina	12.5	86.5
7	Brazil	23.76595745	84.67307692
8	Bulgaria	14.64539007	87.93617021
9	Canada	35.71259843	89.36964981
10	Chile	20.78645833	86.49351521