我有一个条形图,如果将鼠标悬停在其上,我想在工具提示中看到一个折线图。 到目前为止,我的实现方式。
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title>Simple Bar chart</title>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.min.js"></script>
<style>
body {
font-family: "Arial", sans-serif;
}
.bar {
fill: gray;
/*#5f89ad;*/
}
rect:hover {
fill: #1E90FF;
}
.axis {
font-size: 13px;
}
.axis path,
.axis line {
fill: none;
display: none;
}
.label {
font-size: 13px;
font-weight: bold;
}
text {
font-weight: bold;
}
/*.d3-tip {
line-height: 1;
padding: 6px;
background: wheat;
border-radius: 4px solid black;
font-size: 12px;
}*/
</style>
</head>
<body>
<div id="graphic"></div>
<script>
var data = [{
country: 'Bangladesh',
population_2012: 105905297,
growth: {
year_2013: 42488,
year_2014: 934,
year_2015: 52633,
year_2016: 112822,
year_2017: 160792
}
},
{
country: 'Ethopia',
population_2012: 75656319,
growth: {
year_2013: 1606010,
year_2014: 1606705,
year_2015: 1600666,
year_2016: 1590077,
year_2017: 1580805
}
},
{
country: 'Kenya',
population_2012: 33007327,
growth: {
year_2013: 705153,
year_2014: 703994,
year_2015: 699906,
year_2016: 694295,
year_2017: 687910
}
},
{
country: 'Afghanistan',
population_2012: 23280573,
growth: {
year_2013: 717151,
year_2014: 706082,
year_2015: 665025,
year_2016: 616262,
year_2017: 573643
}
},
{
country: 'Morocco',
population_2012: 13619520,
growth: {
year_2013: 11862,
year_2014: 7997,
year_2015: 391,
year_2016: -8820,
year_2017: -17029
}
}
];
data_growth = [];
for (i = 0; i < data.length; i++) {
data[i]["total_population"] = data[i]["population_2012"] + data[i].growth["year_2013"] + data[i].growth["year_2014"] + data[i].growth["year_2015"] + data[i].growth["year_2016"] + data[i].growth["year_2017"];
data[i]["growth_data"] = [{
"year": 2013,
"growth": (data[i].growth["year_2013"] / (data[i]["population_2012"])) * 100
},
{
"year": 2014,
"growth": (data[i].growth["year_2014"] / (data[i]["population_2012"] + data[i].growth["year_2013"])) * 100
},
{
"year": 2015,
"growth": (data[i].growth["year_2015"] / (data[i]["population_2012"] + data[i].growth["year_2013"] + data[i].growth["year_2014"])) * 100
},
{
"year": 2016,
"growth": (data[i].growth["year_2016"] / (data[i]["population_2012"] + data[i].growth["year_2013"] + data[i].growth["year_2014"] + data[i].growth["year_2015"])) * 100
},
{
"year": 2017,
"growth": (data[i].growth["year_2017"] / (data[i]["population_2012"] + data[i].growth["year_2013"] + data[i].growth["year_2014"] + data[i].growth["year_2015"] + data[i].growth["year_2016"])) * 100
}
];
}
//console.log(data);
//sort bars based on population_2012
data = data.sort(function(a, b) {
return d3.ascending(a.population_2012, b.population_2012);
})
//set up svg using margin conventions - we'll need plenty of room on the left for labels
var margin = {
top: 15,
right: 25,
bottom: 15,
left: 160
};
var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var svg = d3.select("#graphic").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var tool_tip = d3.tip()
.attr("class", "d3-tip")
.offset([20, 670])
.html("<p>This is a SVG inside a tooltip:</p><div id='tipDiv'></div>");
svg.call(tool_tip);
var x = d3.scale.linear()
.range([0, width])
.domain([0, d3.max(data, function(d) {
return d.population_2012;
})]);
var y = d3.scale.ordinal()
.rangeRoundBands([height, 0], .1)
.domain(data.map(function(d) {
return d.country;
}));
//make y axis to show bar countrys
var yAxis = d3.svg.axis()
.scale(y)
//no tick marks
.tickSize(0)
.orient("left");
var gy = svg.append("g")
.attr("class", "y axis")
.call(yAxis)
var bars = svg.selectAll(".bar")
.data(data)
.enter()
.append("g")
//append rects
bars.append("rect")
.attr("class", "bar")
.attr("y", function(d) {
return y(d.country);
})
.attr("height", y.rangeBand())
.attr("x", 0)
.attr("width", function(d) {
return x(d.total_population);
})
.attr('fill', 'gray')
.on('mouseover', function(d) {
/////////draw(d["growth_data"]);
//console.log("d:==>", d);
tool_tip.show();
var tipSVG = d3.select("#tipDiv")
.append("svg")
.attr("width", 300) //200
.attr("height", 200); //50
// set the ranges
//var x = d3.scalePoint().range([0, width]);
var x = d3.scale.ordinal().range([0, width]);
//var y = d3.scaleLinear().range([height, 0]);
var y = d3.scale.ordinal().range([height, 0]);
// text label for the x axis
tipSVG.append("text")
.attr("transform",
"translate(" + (width / 2) + " ," +
(height + margin.top + 20) + ")")
.style("text-anchor", "middle")
.text("Date");
// define the line
var valueline = d3.svg.line()
.x(function(d) {
return x(d.key);
})
.y(function(d) {
return y(d.value);
});
////////////END
d["growth_data"].forEach(function(d) {
d.value = +d.value;
});
/*data.sort(function(a, b) {
return a.value - b.value;
})*/
// Scale the range of the data
x.domain(d["growth_data"].map(function(d) {
return d.key;
}));
y.domain([0, d3.max(d["growth_data"], function(d) {
return d.value;
})]);
// Add the valueline path.
tipSVG.append("path")
.datum(d["growth_data"])
.attr("class", "line")
.attr("d", valueline);
tipSVG.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add the Y Axis
tipSVG.append("g")
.call(d3.axisLeft(y));
})
.on('mouseout', tool_tip.hide);
//add a population_2012 label to the right of each bar
bars.append("text")
.attr("class", "label")
//y position of the label is halfway down the bar
.attr("y", function(d) {
return y(d.country) + y.rangeBand() / 2 + 4;
})
//x position is 3 pixels to the right of the bar
.attr("x", 15
/*(function (d) {
return x(d.population_2012) + 3;
}*/
)
.text(function(d) {
return d.total_population.toLocaleString();
});
</script>
</body>
</html>
由于我是D3的新手,因此我试图在.on('mouseover', )
期间显示折线图,但不够清晰。
使用此代码,我遇到错误,不确定该怎么做:
“消息”:“未捕获的TypeError:d3.axisBottom不是函数”,
当我尝试在tipSVG
中显示简单形状时,它工作正常吗?
有人可以建议我犯什么错误吗?
答案 0 :(得分:0)
我已经解决了问题。由于来自d3.v3和d3.v4的API的混合出现了问题。我将整个代码反向移植到d3.v3实现。 在此处发布此代码,以便如果有人希望在另一个图表的工具提示中看到图表的实现。
这是完整的代码:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title>Question 5 </title>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.min.js"></script>
<style>
body {
font-family: "Arial", sans-serif;
}
.bar {
fill: gray;
/*#5f89ad;*/
}
rect:hover {
fill: #1E90FF;
}
.axis {
font-size: 13px;
}
.axis path,
.axis line {
fill: none;
/*display: none;*/
}
.label {
font-size: 13px;
font-weight: bold;
}
text {
font-weight: bold;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 2px;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
/*.d3-tip {
line-height: 1;
padding: 6px;
background: wheat;
border-radius: 4px solid black;
font-size: 12px;
}*/
</style>
</head>
<body>
<div id="graphic"></div>
<script>
var data = [{
country: 'Bangladesh',
population_2012: 105905297,
growth: {
year_2013: 42488,
year_2014: 934,
year_2015: 52633,
year_2016: 112822,
year_2017: 160792
}
},
{
country: 'Ethopia',
population_2012: 75656319,
growth: {
year_2013: 1606010,
year_2014: 1606705,
year_2015: 1600666,
year_2016: 1590077,
year_2017: 1580805
}
},
{
country: 'Kenya',
population_2012: 33007327,
growth: {
year_2013: 705153,
year_2014: 703994,
year_2015: 699906,
year_2016: 694295,
year_2017: 687910
}
},
{
country: 'Afghanistan',
population_2012: 23280573,
growth: {
year_2013: 717151,
year_2014: 706082,
year_2015: 665025,
year_2016: 616262,
year_2017: 573643
}
},
{
country: 'Morocco',
population_2012: 13619520,
growth: {
year_2013: 11862,
year_2014: 7997,
year_2015: 391,
year_2016: -8820,
year_2017: -17029
}
}
];
data_growth = [];
for (i = 0; i < data.length; i++) {
data[i]["total_population"] = data[i]["population_2012"] + data[i].growth["year_2013"] + data[i].growth["year_2014"] + data[i].growth["year_2015"] + data[i].growth["year_2016"] + data[i].growth["year_2017"];
data[i]["growth_data"] = [{
"year": 2013,
"growth": (data[i].growth["year_2013"] / (data[i]["population_2012"])) * 100
},
{
"year": 2014,
"growth": (data[i].growth["year_2014"] / (data[i]["population_2012"] + data[i].growth["year_2013"])) * 100
},
{
"year": 2015,
"growth": (data[i].growth["year_2015"] / (data[i]["population_2012"] + data[i].growth["year_2013"] + data[i].growth["year_2014"])) * 100
},
{
"year": 2016,
"growth": (data[i].growth["year_2016"] / (data[i]["population_2012"] + data[i].growth["year_2013"] + data[i].growth["year_2014"] + data[i].growth["year_2015"])) * 100
},
{
"year": 2017,
"growth": (data[i].growth["year_2017"] / (data[i]["population_2012"] + data[i].growth["year_2013"] + data[i].growth["year_2014"] + data[i].growth["year_2015"] + data[i].growth["year_2016"])) * 100
}
];
}
//console.log(data);
//sort bars based on population_2012
data = data.sort(function(a, b) {
return d3.ascending(a.population_2012, b.population_2012);
})
//set up svg using margin conventions - we'll need plenty of room on the left for labels
var margin = {
top: 15,
right: 25,
bottom: 15,
left: 160
};
var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var svg = d3.select("#graphic").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var tool_tip = d3.tip()
.attr("class", "d3-tip")
.offset([20, 670])
.html("<p>Year-wise growth in population for the country:</p><div id='tipDiv' style='border: 1px solid gray;'></div>");
svg.call(tool_tip);
var x = d3.scale.linear()
.range([0, width])
.domain([0, d3.max(data, function(d) {
return d.population_2012;
})]);
var y = d3.scale.ordinal()
.rangeRoundBands([height, 0], .1)
.domain(data.map(function(d) {
return d.country;
}));
//make y axis to show bar countrys
var yAxis = d3.svg.axis()
.scale(y)
//no tick marks
.tickSize(0)
.orient("left");
var gy = svg.append("g")
.attr("class", "y axis")
.call(yAxis)
var bars = svg.selectAll(".bar")
.data(data)
.enter()
.append("g")
//append rects
bars.append("rect")
.attr("class", "bar")
.attr("y", function(d) {
return y(d.country);
})
.attr("height", y.rangeBand())
.attr("x", 0)
.attr("width", function(d) {
return x(d.total_population);
})
.attr('fill', 'gray')
.on('mouseover', function(d) {
//console.log("d:==>", d);
tool_tip.show();
var points_raw = d3.range(10).map(function() {
return {
year: Math.random() * 100,
growth: Math.random() * 100
}
});
//console.log("points-raw:==>", points_raw)
// sort by x, descending
//points = points_raw.sort(function(a, b) { return d3.descending(a.year, b.year); });
//points = points_raw
points = d["growth_data"];
// set up canvas
var margin = {
top: 20,
right: 30,
bottom: 40,
left: 60
},
width = 420 - margin.left - margin.right,
height = 320 - margin.top - margin.bottom;
var x = d3.scale.linear()
.range([0, width])
.domain(points.map(function(d) {
return d.year;
}));;
var y = d3.scale.linear()
.range([height, 0])
.domain([0, d3.max(points, function(d) {
return d.growth;
})]);
var x_axis = d3.svg.axis()
.scale(x)
.ticks(5)
.orient('bottom');
var y_axis = d3.svg.axis()
.scale(y)
.orient('left');
// define line function
var line = d3.svg.line()
.x(function(d) {
return x(d.year);
})
.y(function(d) {
return y(d.growth);
})
/*.interpolate('basis')*/
;
/*points.forEach(function(d) {
d.growth = +d.growth;
});*/
// add svg element
var svg = d3.select('#tipDiv')
.append('svg')
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// determine domain ranges for x/y
x.domain(d3.extent(points, function(d) {
return d.year;
}));
/*x.domain(points.map(function (d) {
return d["year"];
}));
*/
y.domain(d3.extent(points, function(d) {
return d.growth;
}));
// add labeled x-axis
svg.append('g')
.attr('class', 'x axis')
.attr("transform", "translate(0," + height + ")")
.call(x_axis)
.append("text")
.attr("x", width - 6)
.attr("dy", "3em")
/*.style("text-anchor", "end")*/
.text("Year");
// add labeled y-axis
svg.append('g')
.attr('class', 'y axis')
.call(y_axis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0)
.attr("dy", "-3.71em")
.style("text-anchor", "end")
.text("Pct %");
// draw line
svg.append('path')
.datum(points)
.attr('class', 'line')
.attr('d', line);
})
.on('mouseout', tool_tip.hide);
//add a population_2012 label to the right of each bar
bars.append("text")
.attr("class", "label")
//y position of the label is halfway down the bar
.attr("y", function(d) {
return y(d.country) + y.rangeBand() / 2 + 4;
})
//x position is 3 pixels to the right of the bar
.attr("x", 15
/*(function (d) {
return x(d.population_2012) + 3;
}*/
)
.text(function(d) {
return d.total_population.toLocaleString();
});
</script>
</body>
</html>