2017-06-08 7 views
0

多次元折れ線グラフを作成するための角度ベースのd3指示があります。この指令の中には、mouseovermouseenter、およびmousemoveのイベントがあります。何らかの理由で、彼らは同じディレクティブが座っている別のdivに出血します。私が1つのチャートにマウスカーソルを合わせると、その両方に円が描かれます。それを制御する方法はありますか?誰かが私に説明することができますどのようにスコープがそのように出血が起こるのですか?d3.jsスコープが出血する可能性がある

enter image description here

ここD3ディレクティブです:

angular.module('MissionControlApp').directive('d3MultiSeriesLine', ['d3', function(d3) { 
    return { 
     restrict: 'E', 
     scope: { 
      data: '=', 
      keys: '=', 
      onClick: '&d3OnClick' 
     }, 
     link: function(scope, ele) { 
      var svg = d3.select(ele[0]) 
       .append("svg") 
       .attr("width", "100%"); 

      // on window resize, re-render d3 canvas 
      window.onresize = function() { 
       return scope.$apply(); 
      }; 
      scope.$watch(function(){ 
        return angular.element(window)[0].innerWidth; 
       }, function(){ 
        return scope.render(scope.data); 
       } 
      ); 

      // watch for data changes and re-render 
      scope.$watch("data", function(newVals) { 
       if(!newVals) return; 
       return scope.render(newVals); 
      }, true); 

      scope.render = function (data) { 
       if(!data) return; 

       svg.selectAll("*").remove(); 

       // setup variables 
       var width, height; 
       var margin = {top: 5, right: 10, bottom: 20, left: 30}; 

       width = d3.select(ele[0])[0][0].offsetWidth - margin.left - margin.right; 
       height = 300 - margin.top - margin.bottom; 

       // set the height based on the calculations above 
       svg.attr('height', height + margin.top + margin.bottom); 

       var parseDate = d3.time.format('%Y-%m-%dT%H:%M:%S.%LZ').parse; 
       var dateFormat = d3.time.format("%d %b"); 

       var x = d3.time.scale() 
        .range([0, width]); 

       var y = d3.scale.linear() 
        .range([height, 0]); 

       var color = d3.scale.category10(); 

       var xAxis = d3.svg.axis() 
        .scale(x) 
        .orient("bottom") 
        .ticks(6) 
        .tickFormat(dateFormat); 

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

       var line = d3.svg.line() 
        .interpolate("basis") 
        .x(function (d) { return x(d.date); }) 
        .y(function (d) { return y(d.value); }); 

       color.domain(scope.keys); 

       data.forEach(function (d) { d.date = parseDate(d.createdOn) }); 

       x.domain(d3.extent(data, function(d) { return d.date; })); 

       var lineData = color.domain().map(function(name){ 
        return { 
         name: name, 
         values: data.map(function (d) { 
          return {date: parseDate(d.createdOn), value: +d[name]}; 
         }) 
        } 
       }); 

       var maxValue = d3.max(lineData, function(c) { 
        return d3.max(c.values, function(v) { 
         return v.value; 
        }); 
       }); 

       y.domain([0, maxValue + 20]); 

       // Add the X Axis 
       svg.append("g") 
        .attr("class", "axisMain") 
        .attr("transform", "translate(" + margin.left + "," + (height + margin.top) + ")") 
        .call(xAxis); 

       // Add the Y Axis 
       svg.append("g") 
        .attr("class", "axisMain") 
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")") 
        .call(yAxis); 

       var svgLine = svg.selectAll(".city") 
        .data(lineData) 
        .enter().append("g") 
        .attr("class", "city"); 

       svgLine.append("path") 
        .attr("class", "line") 
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")") 
        .attr("d", function(d) { return line(d.values); }) 
        .style("stroke", function(d) { return color(d.name); }) 
        .attr("stroke-width", 1.5) 
        .attr("fill", "none") 
        .style("opacity", 0) 
        .transition() 
        .duration(1500) 
        .style("opacity", 1); 

       svgLine.append("text") 
        .datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; }) 
        .attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.value) + ")"; }) 
        .attr("x", margin.left) 
        .attr("y", -2) 
        .attr("text-anchor", "end") 
        .attr("dy", ".35em") 
        .text(function(d) { return d.name; }); 

       var mouseG = svg.append("g") 
        .attr("class", "mouse-over-effects"); 

       mouseG.append("path") // this is the black vertical line to follow mouse 
        .attr("class", "mouse-line") 
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")") 
        .style("stroke", "grey") 
        .style("stroke-width", "1px") 
        .style("stroke-dasharray", "3,3") 
        .style("opacity", "0"); 

       var lines = document.getElementsByClassName('line'); 

       var mousePerLine = mouseG.selectAll('.mouse-per-line') 
        .data(lineData) 
        .enter() 
        .append("g") 
        .attr("class", "mouse-per-line"); 

       mousePerLine.append("circle") 
        .attr("r", 6) 
        .style("stroke", function(d) { return color(d.name); }) 
        .style("fill", "none") 
        .style("stroke-width", "1px") 
        .style("opacity", "0"); 

       mousePerLine.append("text") 
        .attr("transform", "translate(10,-6)"); 

       mouseG.append('svg:rect') // append a rect to catch mouse movements on canvas 
        .attr('width', width) // can't catch mouse events on a g element 
        .attr('height', height) 
        .attr('fill', 'none') 
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")") 
        .attr('pointer-events', 'all') 
        .on('mouseout', function() { // on mouse out hide line, circles and text 
         d3.select(".mouse-line") 
          .style("opacity", "0"); 
         d3.selectAll(".mouse-per-line circle") 
          .style("opacity", "0"); 
         d3.selectAll(".mouse-per-line text") 
          .style("opacity", "0"); 
        }) 
        .on('mouseover', function() { // on mouse in show line, circles and text 
         d3.select(".mouse-line") 
          .style("opacity", "1"); 
         d3.selectAll(".mouse-per-line circle") 
          .style("opacity", "1"); 
         d3.selectAll(".mouse-per-line text") 
          .style("opacity", "1"); 
        }) 
        .on('mousemove', function() { // mouse moving over canvas 
         var mouse = d3.mouse(this); 
         d3.select(".mouse-line") 
          .attr("d", function() { 
           var d = "M" + mouse[0] + "," + height; 
           d += " " + mouse[0] + "," + 0; 
           return d; 
          }); 

         d3.selectAll(".mouse-per-line") 
          .attr("transform", function(d, i) { 
           console.log(width/mouse[0]); 
           var xDate = x.invert(mouse[0]), 
            bisect = d3.bisector(function(d) { return d.date; }).right; 
           bisect(d.values, xDate); 

           var beginning = 0, 
            end = lines[i].getTotalLength(); 

           var pos; 
           var target; 
           while (true) { 
            target = Math.floor((beginning + end)/2); 
            pos = lines[i].getPointAtLength(target); 
            if ((target === end || target === beginning) && pos.x !== mouse[0]) { 
             break; 
            } 
            if (pos.x > mouse[0]) end = target; 
            else if (pos.x < mouse[0]) beginning = target; 
            else break; //position found 
           } 

           d3.select(this).select('text') 
            .text(y.invert(pos.y).toFixed(2)); 

           return "translate(" + (mouse[0]+margin.left) + "," + (pos.y + margin.top) +")"; 
          }); 
        }); 
      }; 
     } 
    }; 
}]); 

ここではHTMLコードがあります:

<div class="row"> 
    <div class="panel-group" id="p1"> 
     <div class="panel panel-default"> 
      <div class="panel-heading" data-toggle="collapse" data-parent="#p1" data-target="#collapseP1"> 
       <h4 class="panel-title">Views/Views on Sheet</h4> 
      </div> 
      <div id="collapseP1" class="panel-collapse collapse in"> 
       <div class="panel-body"> 
        <d3-multi-series-line data="vm.d3ViewStatsData" keys="vm.ViewKeys" d3-on-click="vm.d3OnClick(item)"></d3-multi-series-line> 
       </div> 
      </div> 
     </div> 
    </div> 
</div> 
<div class="row"> 
    <div class="panel-group" id="p2"> 
     <div class="panel panel-default"> 
      <div class="panel-heading" data-toggle="collapse" data-parent="#p2" data-target="#collapseP2"> 
       <h4 class="panel-title">Schedules/Schedules on Sheet</h4> 
      </div> 
      <div id="collapseP2" class="panel-collapse collapse in"> 
       <div class="panel-body"> 
        <d3-multi-series-line data="vm.d3ViewStatsData" keys="vm.ScheduleKeys" d3-on-click="vm.d3OnClick(item)"></d3-multi-series-line> 
       </div> 
      </div> 
     </div> 
    </div> 
</div> 

答えて

1

それは私の古いコードの一部です:)

私はもともと、ことを書いたとき、ドキュメント内に1つのグラフを想定しました。そこには、文書全体で物事を選択/発見するいくつかの行があります。以下のような行:

var lines = document.getElementsByClassName('line'); 

そして

d3.selectAll(".mouse-per-line") 

は、元elem[0]オフに基づいて選択されておらず、したがって、あなたの指示に限定されていません。

var lines = []; 
svg.selectAll('line').each(function(){ 
    lines.append(this); 
}); 
+0

マーク、おかげでGitHubの上でそれを共有するために開始する:

簡単に修正がすべてd3.select...svg.select...と交換し、このような何かをラインラインを交換することです。はい、私はマイクのブロックのページからこれの一部を得ました。私はあなたがマルチシリーズオーバレイのために最も好きだったので、私はそれを使い始めました。あなたが提案している変更を見て、あなたに知らせます。選択についてあなたが言っていることは、完璧な意味があります。 – konrad

+1

あなたの提案は素晴らしいです。唯一の変更は 'line'クラスですべてのオブジェクトをすべて選択する必要があることです。' svg.selectAll( ".line") '他のすべてがうまくいきます! – konrad

関連する問題