d3 鼠标悬停事件不适用于所有矩形
d3 mouseover event doesnot work for all rect
我有一个带有鼠标悬停事件的简单条形图。在数据更新工作之前,代码仅在函数 changeData 之外。但是在数据发生变化后,仅在函数内部运行代码。
我如何编写函数来处理所有矩形的 mouseover/out?
使用按钮 OpacityNow 我可以更改所有矩形的不透明度,无论数据是否已更改。
感谢您的帮助。
var myCanvas1 = d3.select("#chart1")
.append("svg")
.attr("width", svgWidth + margin.left + margin.right)
.attr("height", svgHeight + margin.top + margin.bottom)
.style("background", "aliceblue")
.append("g")
.attr("transform","translate(" + margin.left + "," + margin.top + ")")
.append("g");
//append rectangles to svg container
var Bar = myCanvas1.selectAll("rect")
.data(dataArray1)
.enter()
.append("rect")
.style("fill", "steelblue")
.attr("x", function(d, i) { return x(i); })
.attr("width", x.bandwidth())
.attr("y", function(d) { return (svgHeight - y(+d.balance)); } )
.attr("height", function(d) { return y(+d.balance); })
//.on("mouseover", function() {d3.select(this).attr("opacity", 0.5)})
//.on("mouseout", function() {d3.select(this).attr("opacity", 1)});
//function for button click event
function changeData(myDataArray) {
var Bars = myCanvas1.selectAll("rect");
var NewBars = Bars.data(eval(myDataArray));
//enter new data
NewBars.enter()
.append("rect")
.style("fill", "steelblue")
//.on("mouseover", function() {d3.select(this).attr("opacity", 0.5)})
//.on("mouseout", function() {d3.select(this).attr("opacity", 1)})
.transition()
.duration(duration1)
.attr("x", function(d, i) { return x(i); })
.attr("width", x.bandwidth())
.attr("y", function(d) { return (svgHeight - y(+d.balance)); } )
.attr("height", function(d) { return y(+d.balance); });
//exit data
NewBars.exit()
.remove();
//update data
NewBars.transition()
.duration(duration1)
.style("fill", "steelblue")
.attr("x", function(d, i) { return x(i); })
.attr("width", x.bandwidth())
.attr("y", function(d) { return (svgHeight - y(+d.balance)); } )
.attr("height", function(d) { return y(+d.balance); });
//mouseover and mouseout event functions
d3.select("#chart1").select("svg").selectAll("rect").on("mouseover", function(d) { d3.select(this).attr("opacity", 0.3)});
d3.select("#chart1").select("svg").selectAll("rect").on("mouseout", function(d) { d3.select(this).attr("opacity", 1)});
};
//mouseover and mouseout event functions
d3.select("#chart1").select("svg").selectAll("rect").on("mouseover", function(d) { d3.select(this).style("fill", "red")});
d3.select("#chart1").select("svg").selectAll("rect").on("mouseout", function(d) { d3.select(this).style("fill", "green")});
//function click button to change opacity in all rects
function OpacityNow() {
d3.select("#chart1").select("svg").selectAll("rect").style("opacity", 0.3);
};
//function click button to change color in all rects
function ColorNow() {
d3.select("#chart1").select("svg").selectAll("rect").style("fill", "green");
};
这是预期的行为。与单击按钮后运行的按钮代码不同,鼠标悬停代码将事件处理程序绑定到当时 SVG 中存在的 <rect>
元素.
这里有一些代码来演示它。
假设我们有这个模式:
//code for creating the bars
.on("mouseover", function(){ ... }//mouseover block, outside 'update'
update();
function update(){
//code for updating the bars
}
在这种情况下,鼠标悬停将处理在更新函数运行之前创建的条。
这是一个向您展示的演示。您可以看到鼠标悬停最初适用于所有矩形,但是当创建新矩形时,它不再起作用:
var width = 400, height = 400;
var margin = {top:0, right:0, bottom:0, left:30};
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var xScale = d3.scaleLinear()
.range([margin.left, width - margin.right]);
var yScale = d3.scaleBand()
.range([margin.top, height - margin.bottom])
.paddingInner(0.2);
var yAxis = d3.axisLeft(yScale)
.tickSizeOuter(0);
var letters = "ABCDEFGHIJ".split("");
var color = d3.scaleSequential(d3.interpolateViridis)
.domain([0, 10]);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + margin.left + ",0)")
.call(yAxis);
draw();
function draw(){
var data = getData();
xScale.domain([0, d3.max(data, function(d){ return d.value})]);
yScale.domain(data.map(function(d){ return d.title}));
var bars = svg.selectAll(".bars")
.data(data, function(d){ return d.title});
bars.exit()
.transition()
.duration(1000)
.attr("width", 0)
.remove();
bars.enter()
.append("rect")
.attr("class", "bars")
.attr("x", xScale(0) + 1)
.attr("y", function(d){ return yScale(d.title)})
.attr("width", 0)
.attr("height", yScale.bandwidth())
.attr("fill", function(d){ return color(letters.indexOf(d.title)+1)})
.merge(bars).transition()
.duration(1000)
.delay(1000)
.attr("y", function(d){ return yScale(d.title)})
.attr("width", function(d){ return xScale(d.value)});
d3.transition(svg).select(".y.axis")
.transition()
.duration(1000)
.delay(750)
.call(yAxis);
}
function getData(){
var title = "ABCDEFGHIJ".split("");
var data = [];
for(var i = 0; i < 5; i++){
var index = Math.floor(Math.random()*title.length);
data.push({title: title[index],
value: Math.floor(Math.random()*100)});
title.splice(index,1);
}
data = data.sort(function(a,b){ return d3.ascending(a.title,b.title)});
return data;
};
setInterval(draw, 3000);
d3.selectAll("rect").on("mouseover", function(){
d3.select(this).attr("opacity", .5)
}).on("mouseout", function(){
d3.select(this).attr("opacity", 1)
});
<script src="https://d3js.org/d3.v4.min.js"></script>
现在,让我们做另一个模式:
//code for creating the bars
update();
function update(){
//code for updating the bars
.on("mouseover", function(){ ... }//mouseover block, inside 'update'
}
在这种情况下,鼠标悬停仅在 函数 update
被调用后有效。这是另一个演示,函数将在 5 秒后调用:
var width = 400, height = 400;
var margin = {top:0, right:0, bottom:0, left:30};
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var xScale = d3.scaleLinear()
.range([margin.left, width - margin.right]);
var yScale = d3.scaleBand()
.range([margin.top, height - margin.bottom])
.paddingInner(0.2);
var yAxis = d3.axisLeft(yScale)
.tickSizeOuter(0);
var letters = "ABCDEFGHIJ".split("");
var color = d3.scaleSequential(d3.interpolateViridis)
.domain([0, 10]);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + margin.left + ",0)")
.call(yAxis);
var data = getData();
xScale.domain([0, d3.max(data, function(d){ return d.value})]);
yScale.domain(data.map(function(d){ return d.title}));
var bars = svg.selectAll(".bars")
.data(data, function(d){ return d.title});
bars.exit()
.transition()
.duration(1000)
.attr("width", 0)
.remove();
bars.enter()
.append("rect")
.attr("class", "bars")
.attr("x", xScale(0) + 1)
.attr("y", function(d){ return yScale(d.title)})
.attr("width", 0)
.attr("height", yScale.bandwidth())
.attr("fill", function(d){ return color(letters.indexOf(d.title)+1)})
.merge(bars).transition()
.duration(1000)
.delay(1000)
.attr("y", function(d){ return yScale(d.title)})
.attr("width", function(d){ return xScale(d.value)});
d3.transition(svg).select(".y.axis")
.transition()
.duration(1000)
.delay(750)
.call(yAxis);
function draw(){
var data = getData();
xScale.domain([0, d3.max(data, function(d){ return d.value})]);
yScale.domain(data.map(function(d){ return d.title}));
var bars = svg.selectAll(".bars")
.data(data, function(d){ return d.title});
bars.exit()
.transition()
.duration(1000)
.attr("width", 0)
.remove();
bars.enter()
.append("rect")
.attr("class", "bars")
.attr("x", xScale(0) + 1)
.attr("y", function(d){ return yScale(d.title)})
.attr("width", 0)
.attr("height", yScale.bandwidth())
.attr("fill", function(d){ return color(letters.indexOf(d.title)+1)})
.merge(bars).transition()
.duration(1000)
.delay(1000)
.attr("y", function(d){ return yScale(d.title)})
.attr("width", function(d){ return xScale(d.value)});
d3.selectAll("rect").on("mouseover", function(){
d3.select(this).attr("opacity", .5)
}).on("mouseout", function(){
d3.select(this).attr("opacity", 1)
});
d3.transition(svg).select(".y.axis")
.transition()
.duration(1000)
.delay(750)
.call(yAxis);
}
function getData(){
var title = "ABCDEFGHIJ".split("");
var data = [];
for(var i = 0; i < 5; i++){
var index = Math.floor(Math.random()*title.length);
data.push({title: title[index],
value: Math.floor(Math.random()*100)});
title.splice(index,1);
}
data = data.sort(function(a,b){ return d3.ascending(a.title,b.title)});
return data;
};
setInterval(draw, 5000);
<script src="https://d3js.org/d3.v4.min.js"></script>
只有在那之后,鼠标悬停才会起作用。
正如我之前所说,该按钮将适用于在 update
函数之前或之后创建的所有矩形,因为它会在按下按钮时选择 SVG 中显示的矩形.
如果你不想重复代码(以防你的mouseover
和mouseout
函数变大),你可以单独设置函数:
//code for creating the bars
.on("mouseover", mouseover)//calls 'mouseover'
.on("mouseout", mouseout)//calls 'mouseout'
function update(){
//code for updating the bars
.on("mouseover", mouseover)//calls 'mouseover'
.on("mouseout", mouseout)//calls 'mouseout'
}
function mouseover(){ ... }
function mouseout(){ ... }
这是演示:
var width = 400, height = 400;
var margin = {top:0, right:0, bottom:0, left:30};
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var xScale = d3.scaleLinear()
.range([margin.left, width - margin.right]);
var yScale = d3.scaleBand()
.range([margin.top, height - margin.bottom])
.paddingInner(0.2);
var yAxis = d3.axisLeft(yScale)
.tickSizeOuter(0);
var letters = "ABCDEFGHIJ".split("");
var color = d3.scaleSequential(d3.interpolateViridis)
.domain([0, 10]);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + margin.left + ",0)")
.call(yAxis);
draw();
function draw(){
var data = getData();
xScale.domain([0, d3.max(data, function(d){ return d.value})]);
yScale.domain(data.map(function(d){ return d.title}));
var bars = svg.selectAll(".bars")
.data(data, function(d){ return d.title});
bars.exit()
.transition()
.duration(1000)
.attr("width", 0)
.remove();
bars.enter()
.append("rect")
.attr("class", "bars")
.attr("x", xScale(0) + 1)
.attr("y", function(d){ return yScale(d.title)})
.attr("width", 0)
.attr("height", yScale.bandwidth())
.attr("fill", function(d){ return color(letters.indexOf(d.title)+1)})
.merge(bars).transition()
.duration(1000)
.delay(1000)
.attr("y", function(d){ return yScale(d.title)})
.attr("width", function(d){ return xScale(d.value)});
d3.selectAll("rect").on("mouseover", mouseover).on("mouseout", mouseout);
d3.transition(svg).select(".y.axis")
.transition()
.duration(1000)
.delay(750)
.call(yAxis);
}
function getData(){
var title = "ABCDEFGHIJ".split("");
var data = [];
for(var i = 0; i < 5; i++){
var index = Math.floor(Math.random()*title.length);
data.push({title: title[index],
value: Math.floor(Math.random()*100)});
title.splice(index,1);
}
data = data.sort(function(a,b){ return d3.ascending(a.title,b.title)});
return data;
};
setInterval(draw, 3000);
d3.selectAll("rect").on("mouseover", mouseover).on("mouseout", mouseout);
function mouseover(){
d3.select(this).attr("opacity", .5);
}
function mouseout(){
d3.select(this).attr("opacity", 1);
}
<script src="https://d3js.org/d3.v4.min.js"></script>
我有一个带有鼠标悬停事件的简单条形图。在数据更新工作之前,代码仅在函数 changeData 之外。但是在数据发生变化后,仅在函数内部运行代码。 我如何编写函数来处理所有矩形的 mouseover/out?
使用按钮 OpacityNow 我可以更改所有矩形的不透明度,无论数据是否已更改。
感谢您的帮助。
var myCanvas1 = d3.select("#chart1")
.append("svg")
.attr("width", svgWidth + margin.left + margin.right)
.attr("height", svgHeight + margin.top + margin.bottom)
.style("background", "aliceblue")
.append("g")
.attr("transform","translate(" + margin.left + "," + margin.top + ")")
.append("g");
//append rectangles to svg container
var Bar = myCanvas1.selectAll("rect")
.data(dataArray1)
.enter()
.append("rect")
.style("fill", "steelblue")
.attr("x", function(d, i) { return x(i); })
.attr("width", x.bandwidth())
.attr("y", function(d) { return (svgHeight - y(+d.balance)); } )
.attr("height", function(d) { return y(+d.balance); })
//.on("mouseover", function() {d3.select(this).attr("opacity", 0.5)})
//.on("mouseout", function() {d3.select(this).attr("opacity", 1)});
//function for button click event
function changeData(myDataArray) {
var Bars = myCanvas1.selectAll("rect");
var NewBars = Bars.data(eval(myDataArray));
//enter new data
NewBars.enter()
.append("rect")
.style("fill", "steelblue")
//.on("mouseover", function() {d3.select(this).attr("opacity", 0.5)})
//.on("mouseout", function() {d3.select(this).attr("opacity", 1)})
.transition()
.duration(duration1)
.attr("x", function(d, i) { return x(i); })
.attr("width", x.bandwidth())
.attr("y", function(d) { return (svgHeight - y(+d.balance)); } )
.attr("height", function(d) { return y(+d.balance); });
//exit data
NewBars.exit()
.remove();
//update data
NewBars.transition()
.duration(duration1)
.style("fill", "steelblue")
.attr("x", function(d, i) { return x(i); })
.attr("width", x.bandwidth())
.attr("y", function(d) { return (svgHeight - y(+d.balance)); } )
.attr("height", function(d) { return y(+d.balance); });
//mouseover and mouseout event functions
d3.select("#chart1").select("svg").selectAll("rect").on("mouseover", function(d) { d3.select(this).attr("opacity", 0.3)});
d3.select("#chart1").select("svg").selectAll("rect").on("mouseout", function(d) { d3.select(this).attr("opacity", 1)});
};
//mouseover and mouseout event functions
d3.select("#chart1").select("svg").selectAll("rect").on("mouseover", function(d) { d3.select(this).style("fill", "red")});
d3.select("#chart1").select("svg").selectAll("rect").on("mouseout", function(d) { d3.select(this).style("fill", "green")});
//function click button to change opacity in all rects
function OpacityNow() {
d3.select("#chart1").select("svg").selectAll("rect").style("opacity", 0.3);
};
//function click button to change color in all rects
function ColorNow() {
d3.select("#chart1").select("svg").selectAll("rect").style("fill", "green");
};
这是预期的行为。与单击按钮后运行的按钮代码不同,鼠标悬停代码将事件处理程序绑定到当时 SVG 中存在的 <rect>
元素.
这里有一些代码来演示它。
假设我们有这个模式:
//code for creating the bars
.on("mouseover", function(){ ... }//mouseover block, outside 'update'
update();
function update(){
//code for updating the bars
}
在这种情况下,鼠标悬停将处理在更新函数运行之前创建的条。
这是一个向您展示的演示。您可以看到鼠标悬停最初适用于所有矩形,但是当创建新矩形时,它不再起作用:
var width = 400, height = 400;
var margin = {top:0, right:0, bottom:0, left:30};
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var xScale = d3.scaleLinear()
.range([margin.left, width - margin.right]);
var yScale = d3.scaleBand()
.range([margin.top, height - margin.bottom])
.paddingInner(0.2);
var yAxis = d3.axisLeft(yScale)
.tickSizeOuter(0);
var letters = "ABCDEFGHIJ".split("");
var color = d3.scaleSequential(d3.interpolateViridis)
.domain([0, 10]);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + margin.left + ",0)")
.call(yAxis);
draw();
function draw(){
var data = getData();
xScale.domain([0, d3.max(data, function(d){ return d.value})]);
yScale.domain(data.map(function(d){ return d.title}));
var bars = svg.selectAll(".bars")
.data(data, function(d){ return d.title});
bars.exit()
.transition()
.duration(1000)
.attr("width", 0)
.remove();
bars.enter()
.append("rect")
.attr("class", "bars")
.attr("x", xScale(0) + 1)
.attr("y", function(d){ return yScale(d.title)})
.attr("width", 0)
.attr("height", yScale.bandwidth())
.attr("fill", function(d){ return color(letters.indexOf(d.title)+1)})
.merge(bars).transition()
.duration(1000)
.delay(1000)
.attr("y", function(d){ return yScale(d.title)})
.attr("width", function(d){ return xScale(d.value)});
d3.transition(svg).select(".y.axis")
.transition()
.duration(1000)
.delay(750)
.call(yAxis);
}
function getData(){
var title = "ABCDEFGHIJ".split("");
var data = [];
for(var i = 0; i < 5; i++){
var index = Math.floor(Math.random()*title.length);
data.push({title: title[index],
value: Math.floor(Math.random()*100)});
title.splice(index,1);
}
data = data.sort(function(a,b){ return d3.ascending(a.title,b.title)});
return data;
};
setInterval(draw, 3000);
d3.selectAll("rect").on("mouseover", function(){
d3.select(this).attr("opacity", .5)
}).on("mouseout", function(){
d3.select(this).attr("opacity", 1)
});
<script src="https://d3js.org/d3.v4.min.js"></script>
现在,让我们做另一个模式:
//code for creating the bars
update();
function update(){
//code for updating the bars
.on("mouseover", function(){ ... }//mouseover block, inside 'update'
}
在这种情况下,鼠标悬停仅在 函数 update
被调用后有效。这是另一个演示,函数将在 5 秒后调用:
var width = 400, height = 400;
var margin = {top:0, right:0, bottom:0, left:30};
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var xScale = d3.scaleLinear()
.range([margin.left, width - margin.right]);
var yScale = d3.scaleBand()
.range([margin.top, height - margin.bottom])
.paddingInner(0.2);
var yAxis = d3.axisLeft(yScale)
.tickSizeOuter(0);
var letters = "ABCDEFGHIJ".split("");
var color = d3.scaleSequential(d3.interpolateViridis)
.domain([0, 10]);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + margin.left + ",0)")
.call(yAxis);
var data = getData();
xScale.domain([0, d3.max(data, function(d){ return d.value})]);
yScale.domain(data.map(function(d){ return d.title}));
var bars = svg.selectAll(".bars")
.data(data, function(d){ return d.title});
bars.exit()
.transition()
.duration(1000)
.attr("width", 0)
.remove();
bars.enter()
.append("rect")
.attr("class", "bars")
.attr("x", xScale(0) + 1)
.attr("y", function(d){ return yScale(d.title)})
.attr("width", 0)
.attr("height", yScale.bandwidth())
.attr("fill", function(d){ return color(letters.indexOf(d.title)+1)})
.merge(bars).transition()
.duration(1000)
.delay(1000)
.attr("y", function(d){ return yScale(d.title)})
.attr("width", function(d){ return xScale(d.value)});
d3.transition(svg).select(".y.axis")
.transition()
.duration(1000)
.delay(750)
.call(yAxis);
function draw(){
var data = getData();
xScale.domain([0, d3.max(data, function(d){ return d.value})]);
yScale.domain(data.map(function(d){ return d.title}));
var bars = svg.selectAll(".bars")
.data(data, function(d){ return d.title});
bars.exit()
.transition()
.duration(1000)
.attr("width", 0)
.remove();
bars.enter()
.append("rect")
.attr("class", "bars")
.attr("x", xScale(0) + 1)
.attr("y", function(d){ return yScale(d.title)})
.attr("width", 0)
.attr("height", yScale.bandwidth())
.attr("fill", function(d){ return color(letters.indexOf(d.title)+1)})
.merge(bars).transition()
.duration(1000)
.delay(1000)
.attr("y", function(d){ return yScale(d.title)})
.attr("width", function(d){ return xScale(d.value)});
d3.selectAll("rect").on("mouseover", function(){
d3.select(this).attr("opacity", .5)
}).on("mouseout", function(){
d3.select(this).attr("opacity", 1)
});
d3.transition(svg).select(".y.axis")
.transition()
.duration(1000)
.delay(750)
.call(yAxis);
}
function getData(){
var title = "ABCDEFGHIJ".split("");
var data = [];
for(var i = 0; i < 5; i++){
var index = Math.floor(Math.random()*title.length);
data.push({title: title[index],
value: Math.floor(Math.random()*100)});
title.splice(index,1);
}
data = data.sort(function(a,b){ return d3.ascending(a.title,b.title)});
return data;
};
setInterval(draw, 5000);
<script src="https://d3js.org/d3.v4.min.js"></script>
只有在那之后,鼠标悬停才会起作用。
正如我之前所说,该按钮将适用于在 update
函数之前或之后创建的所有矩形,因为它会在按下按钮时选择 SVG 中显示的矩形.
如果你不想重复代码(以防你的mouseover
和mouseout
函数变大),你可以单独设置函数:
//code for creating the bars
.on("mouseover", mouseover)//calls 'mouseover'
.on("mouseout", mouseout)//calls 'mouseout'
function update(){
//code for updating the bars
.on("mouseover", mouseover)//calls 'mouseover'
.on("mouseout", mouseout)//calls 'mouseout'
}
function mouseover(){ ... }
function mouseout(){ ... }
这是演示:
var width = 400, height = 400;
var margin = {top:0, right:0, bottom:0, left:30};
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var xScale = d3.scaleLinear()
.range([margin.left, width - margin.right]);
var yScale = d3.scaleBand()
.range([margin.top, height - margin.bottom])
.paddingInner(0.2);
var yAxis = d3.axisLeft(yScale)
.tickSizeOuter(0);
var letters = "ABCDEFGHIJ".split("");
var color = d3.scaleSequential(d3.interpolateViridis)
.domain([0, 10]);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + margin.left + ",0)")
.call(yAxis);
draw();
function draw(){
var data = getData();
xScale.domain([0, d3.max(data, function(d){ return d.value})]);
yScale.domain(data.map(function(d){ return d.title}));
var bars = svg.selectAll(".bars")
.data(data, function(d){ return d.title});
bars.exit()
.transition()
.duration(1000)
.attr("width", 0)
.remove();
bars.enter()
.append("rect")
.attr("class", "bars")
.attr("x", xScale(0) + 1)
.attr("y", function(d){ return yScale(d.title)})
.attr("width", 0)
.attr("height", yScale.bandwidth())
.attr("fill", function(d){ return color(letters.indexOf(d.title)+1)})
.merge(bars).transition()
.duration(1000)
.delay(1000)
.attr("y", function(d){ return yScale(d.title)})
.attr("width", function(d){ return xScale(d.value)});
d3.selectAll("rect").on("mouseover", mouseover).on("mouseout", mouseout);
d3.transition(svg).select(".y.axis")
.transition()
.duration(1000)
.delay(750)
.call(yAxis);
}
function getData(){
var title = "ABCDEFGHIJ".split("");
var data = [];
for(var i = 0; i < 5; i++){
var index = Math.floor(Math.random()*title.length);
data.push({title: title[index],
value: Math.floor(Math.random()*100)});
title.splice(index,1);
}
data = data.sort(function(a,b){ return d3.ascending(a.title,b.title)});
return data;
};
setInterval(draw, 3000);
d3.selectAll("rect").on("mouseover", mouseover).on("mouseout", mouseout);
function mouseover(){
d3.select(this).attr("opacity", .5);
}
function mouseout(){
d3.select(this).attr("opacity", 1);
}
<script src="https://d3js.org/d3.v4.min.js"></script>