问题描述
我有一个条形图,如果将鼠标悬停在其上,我想在工具提示中看到一个折线图。 到目前为止,我的实现。
<!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>
我正在尝试在.on('mouseover', )
期间显示折线图.on('mouseover', )
并且不太清楚,因为我是D3的新手。
有了这段代码,我得到了错误,并且不确定该怎么做:
“ message”:“未捕获的TypeError:d3.axisBottom不是函数”,
当我尝试在tipSVG
内显示简单形状时,它工作正常吗?
有人可以建议我犯什么错误吗?
1楼
Om Prakash Sao
0
已采纳
2019-02-21 10:56:48
我已经解决了这个问题。 由于来自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>