d3中两个数据源的工具提示问题

时间:2016-08-04 15:01:05

标签: javascript json d3.js

我有一个d3图表,它是从某些json生成的,而json又是由php生成的。所有这一切都运行良好 - PHP正确格式化json和图表正确显示。可以看到here,我包括以下javascript部分的完整代码:

            var margin = {top: 50, right: 150, bottom: 50, left: 150},
            w = 2500 - margin.left - margin.right,
            h = 500 - margin.top - margin.bottom;


var json = <?php echo $json; ?>;

console.log(json);

d3.json("MM_chart.json", function(error, json) {
  if (error) throw error;

           var items = json.items;

           var locations = json.locations;

           var directions = json.stage_directions;

           console.log(items);
           console.log(locations);
           console.log(directions);

            var stage_directions = ([44, 49, 114, 140, 209, 217, 249, 257, 265, 277, 305, 334, 358, 381, 398, 409, 440, 470, 491, 547, 555, 564, 572, 587, 614, 630, 640, 691, 704, 725, 743, 775, 793, 818, 823, 841, 845, 868, 872, 888, 902, 910, 920, 925, 963, 993, 1005, 1023, 1031, 1047, 1061, 1096, 1125, 1133, 1143, 1178, 1210, 1228, 1281, 1293, 1336, 1349, 1376, 1395, 1439, 1446, 1454, 1538, 1554, 1562, 1578, 1598, 1610, 1618, 1642, 1646, 1716, 1725, 1743, 1781, 1791, 1797, 1843, 1863, 1887, 1915, 1923, 1939 ,1972, 1989, 2019, 2031, 2039, 2045, 2073, 2085, 2101, 2123]);

            var x = d3.scale.linear()
            .domain([0, 2200])
            .range([0, w]);

            var y = d3.scale.ordinal()
            .domain(locations.map(function(d) {return d["location"];})) 
            .rangeBands([0, h]);

            var yAxis = d3.svg.axis()
            .scale(y)
            .orient("left");

            var xAxis = d3.svg.axis()
            .scale(x)
            .orient("bottom");

            var tip = d3.tip()
            .attr('class', 'd3-tip')
            .offset([-10, 0])
            .html(function(d, i) {return console.log(d.line_text) + "<strong>(" + d.starting_line + ")</strong> <i>" + d.character + "</i>: " + d.line_text;});

            var stage_tip = d3.tip()
            .attr('class', 'd3-tip')
            .offset([-10, 0])
            .html(function(d, i) {return console.log(d.direction_text) + "<strong>(" + d.line_after + ") s.d.</strong> <i>" + d.direction_text;});

            var svg = d3.select("body").append("svg")
            .attr("width", w + margin.left + margin.right)
            .attr("height", h + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


            svg.append("text") 
            .attr("transform", "translate(" + (w / 2) + " ," + (h + margin.bottom - 5) +")")
            .style("text-anchor", "middle")
            .text("Line Number");

            var stage_bars = svg.selectAll(".stage_bar")
                .data(directions)
                .enter()
                .append("rect")
                .attr("class", "overlay")
                .attr("class", function(d, i) {return "stage_bar " + d.direction_text;})
                .attr("x", function(d, i) {return d.line_after;})
                .attr("width", 1)
                .attr("height", h)
                .style("fill", "black")
                .style("opacity",0.3)
                .call(stage_tip)
                .on('mouseover', stage_tip.show)
                .on('mouseout',stage_tip.hide);

            svg.append("rect")
            .attr("class", "overlay")
            .attr("x",1)
            .attr("width", 1133)
            .attr("height", h)
            .style ("fill", "red")
            .style ("opacity", 0.1);

            svg.append("rect")
            .attr("class", "overlay")
            .attr("x",1133)
            .attr("width", 857)
            .attr("height", h)
            .style ("fill", "yellow")
            .style ("opacity", 0.1);

            svg.append("rect")
            .attr("class", "overlay")
            .attr("x",1990)
            .attr("width", 134)
            .attr("height", h)
            .style ("fill", "green")
            .style ("opacity", 0.1);

          svg.append("rect")
          .attr("class", "overlay")
          .attr("x",5)
          .attr("y", 10)
          .attr("width", 485)
          .attr("height", 155)
          .style ("fill", "aliceblue")
//              .style ("opacity", 0.1);

            svg.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + h + ")")
            .call(xAxis);

            svg.append("g")
            .attr("class", "y axis")
            .call(yAxis)
            //.call(bars);  

            var bars = svg.selectAll(".bar")
            .data(items)
            .enter()
            .append("rect")
            .attr("class", function(d, i) {return "bar " + d.character;})
            .attr("x", function(d, i) {return d.starting_line;})
            .attr("y", function(d, i) {return y(d.location);})
            .attr("width", function(d, i) {return d.duration;})
            .attr("height", 15)
            .style("fill", function(d,i) {return "#" + d.color;})
            .call(tip)
            .on('mouseover', tip.show)
            .on('mouseout', tip.hide);


                   var listCharacters = d3.set(items.map(function(d) {return d.character})).values();

                   listColors = [];

                   listPositions = [];

                   for (l = 0; l < listCharacters.length; l++) {
                       for (var key in items) {
                           if (listCharacters[l] === items[key].character) {
                               if (listColors.indexOf(items[key].color) > -1) {} else {
                                   listColors.push(items[key].color);
                                   var xlegend = (Math.floor(l / 10) * 100);
                                   var ycounter;
                                   var ylegend;
                                   var oldxlegend;

                                   if (l === 0) {
                                       ycounter = 1;
                                   }

                                   if (ycounter < 10) {
                                       listPositions.push(ycounter * 15);
                                       ycounter++;
                                   } else {
                                       listPositions.push(ycounter * 15);
                                       ycounter = 1;
                                   }

                               }
                           } else {}
                       }
                   }


console.log(listCharacters);
console.log(listColors);
console.log(listPositions);

            var legend = svg.selectAll(".legend")
            .data(listCharacters)
            .enter().append("g")
            .attr("class", "legend")
            .attr("transform", function(d, i) { return "translate(" + (Math.floor(i / 10)  * 105) + ", " + listPositions[i] + ")"; })

            legend.append("rect")
            .attr("x", 10)
            .attr("width", 10)
            .attr("height", 10)
            .attr("fill", function(d,i) {return "#" + listColors[i];});



            legend.append("text")
            .attr("x", 22)
            .attr("y", 5)
            .attr("dy", ".35em")
            .text(function(d,i){ return listCharacters[i]});

            svg.append("g")
            .attr("class", "legend")
            .call(legend)

        });

我的问题是我想要包含两个工具提示,它们是从JSON的两个独立子部分中提取的。工具提示由以下两个var声明定义:

            var tip = d3.tip()
            .attr('class', 'd3-tip')
            .offset([-10, 0])
            .html(function(d, i) {return console.log(d.line_text) + "<strong>(" + d.starting_line + ")</strong> <i>" + d.character + "</i>: " + d.line_text;});

            var stage_tip = d3.tip()
            .attr('class', 'd3-tip')
            .offset([-10, 0])
            .html(function(d, i) {return console.log(d.direction_text) + "<strong>(" + d.line_after + ") s.d.</strong> <i>" + d.direction_text;});

并在两次调用中声明项目和方向的条形图:

    var stage_bars = svg.selectAll(".stage_bar")
        .data(directions)
        .enter()
        .append("rect")
        .attr("class", "overlay")
        .attr("class", function(d, i) {return "stage_bar " + d.direction_text;})
        .attr("x", function(d, i) {return d.line_after;})
        .attr("width", 1)
        .attr("height", h)
        .style("fill", "black")
        .style("opacity",0.3)
        .call(stage_tip)
        .on('mouseover', stage_tip.show)
        .on('mouseout',stage_tip.hide);

    var bars = svg.selectAll(".bar")
        .data(items)
        .enter()
        .append("rect")
        .attr("class", function(d, i) {return "bar " + d.character;})
        .attr("x", function(d, i) {return d.starting_line;})
        .attr("y", function(d, i) {return y(d.location);})
        .attr("width", function(d, i) {return d.duration;})
        .attr("height", 15)
        .style("fill", function(d,i) {return "#" + d.color;})
        .call(tip)
        .on('mouseover', tip.show)
        .on('mouseout', tip.hide);

我的问题是bar的工具提示(调用提示的工具提示)有效,但stage_bars的工具提示(调用stage-tip的工具提示)不起作用。我认为问题在于我在tip和stage_tip中调用了同一个类,但是将其声明为tip以外的其他内容没有任何区别。

我的问题是如何让两个工具提示都起作用。这甚至可能吗?我已经看过似乎这样做的例子,但代码并不清楚。

1 个答案:

答案 0 :(得分:0)

解决方案实际上非常简单。我在svg.append(&#34; rect&#34;)语句之前声明了stage_bars变量,这意味着指示阶段方向的行低于其他对象。因此,鼠标永远不会将鼠标悬停在它们上面以触发工具提示。在这些svg.append语句解决了问题后,将var声明移动到某个位置。