0
多次元折れ線グラフを作成するための角度ベースのd3指示があります。この指令の中には、mouseover
、mouseenter
、およびmousemove
のイベントがあります。何らかの理由で、彼らは同じディレクティブが座っている別のdivに出血します。私が1つのチャートにマウスカーソルを合わせると、その両方に円が描かれます。それを制御する方法はありますか?誰かが私に説明することができますどのようにスコープがそのように出血が起こるのですか?d3.jsスコープが出血する可能性がある
ここ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>
マーク、おかげでGitHubの上でそれを共有するために開始する:
簡単に修正がすべて
d3.select...
svg.select...
と交換し、このような何かをラインラインを交換することです。はい、私はマイクのブロックのページからこれの一部を得ました。私はあなたがマルチシリーズオーバレイのために最も好きだったので、私はそれを使い始めました。あなたが提案している変更を見て、あなたに知らせます。選択についてあなたが言っていることは、完璧な意味があります。 – konradあなたの提案は素晴らしいです。唯一の変更は 'line'クラスですべてのオブジェクトをすべて選択する必要があることです。' svg.selectAll( ".line") '他のすべてがうまくいきます! – konrad