簡體   English   中英

將標題放在D3 SVG元素中的滑塊上方

[英]Put title above slider in D3 svg element

考慮以下:

 var dataAsCsv = `date,col_1,col_2 11/1/2012,1977652,1802851 12/1/2012,1128739,948687 1/1/2013,1201944,1514667 2/1/2013,1863148,1834006 3/1/2013,1314851,1906060 4/1/2013,1283943,1978702 5/1/2013,1127964,1195606 6/1/2013,1773254,977214 7/1/2013,1929574,1127450 8/1/2013,1980411,1808161 9/1/2013,1405691,1182788 10/1/2013,1336790,937890 11/1/2013,1851053,1358400 12/1/2013,1472623,1214610 1/1/2014,1155116,1757052 2/1/2014,1571611,1935038 3/1/2014,1898348,1320348 4/1/2014,1444838,1934789 5/1/2014,1235087,950194 6/1/2014,1272040,1580656 7/1/2014,980781,1680164 8/1/2014,1391291,1115999 9/1/2014,1211125,1542148 10/1/2014,1020824,1782795 11/1/2014,1685081,926612 12/1/2014,1469254,1767071 1/1/2015,1168523,935897 2/1/2015,1602610,1450541 3/1/2015,1830278,1354876 4/1/2015,1275158,1412555 5/1/2015,1560961,1839718 6/1/2015,949948,1587130 7/1/2015,1413765,1494446 8/1/2015,1166141,1305105 9/1/2015,958975,1202219 10/1/2015,902696,1023987 11/1/2015,961441,1865628 12/1/2015,1363145,1954046 1/1/2016,1862878,1470741 2/1/2016,1723891,1042760 3/1/2016,1906747,1169012 4/1/2016,1963364,1927063 5/1/2016,1899735,1936915 6/1/2016,1300369,1430697 7/1/2016,1777108,1401210 8/1/2016,1597045,1566763 9/1/2016,1558287,1140057 10/1/2016,1965665,1953595 11/1/2016,1800438,937551 12/1/2016,1689152,1221895 1/1/2017,1607824,1963282 2/1/2017,1878431,1415658 3/1/2017,1730296,1947106 4/1/2017,1956756,1696780 5/1/2017,1746673,1662892 6/1/2017,989702,1537646 7/1/2017,1098812,1592064 8/1/2017,1861973,1892987 9/1/2017,1129596,1406514 10/1/2017,1528632,1725020 11/1/2017,925850,1795575`; var margin = { top: 50, right: 20, bottom: 50, left: 80 }, width = 1400 - margin.left - margin.right, height = 700 - margin.top - margin.bottom; var svg = d3.select("body").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom); var g = svg.append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // parse the date / time // look at the .csv in Notepad! DO NOT LOOK AT EXCEL! var parseDate = d3.timeParse("%m/%d/%Y"); var sessions_desktop_col = "#CE1126", sessions_mobile_col = "#00B6D0"; var x = d3.scaleTime() .range([0, width - margin.left - margin.right]); var y = d3.scaleLinear().range([height, 0]); var z = d3.scaleOrdinal() .range([sessions_desktop_col, sessions_mobile_col]); // red and blue var xMonthAxis = d3.axisBottom(x) .ticks(d3.timeMonth.every(1)) .tickFormat(d3.timeFormat("%b")); // label every month var xYearAxis = d3.axisBottom(x) .ticks(d3.timeYear.every(1)) .tickFormat(d3.timeFormat("%Y")); // label every year var yAxis = d3.axisLeft(y).tickFormat(d3.format('.2s')).tickSize(-width + margin.left + margin.right); var formatNum = d3.format(","); var barPad = 8; var data = d3.csvParse(dataAsCsv, function(d, i, columns) { for (i = 1, t = 0; i < columns.length; ++i) t += d[columns[i]] = +d[columns[i]]; d.total = t; return d; }); data.forEach(function(d) { d.date = parseDate(d.date); }); var keys = data.columns.slice(1); data.sort(function(a, b) { return b.date - a.date; }); x.domain(d3.extent(data, function(d) { return d.date })); var max = x.domain()[1]; var min = x.domain()[0]; var datePlusOneMonth = d3.timeDay.offset(d3.timeMonth.offset(max, 1), -1); // last day of current month: move up one month, back one day x.domain([min, datePlusOneMonth]); y.domain([0, d3.max(data, function(d) { return d.total; })]).nice(); z.domain(keys); // x-axis var monthAxis = g.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xMonthAxis); var defaultSliderValue = 25; // calculate offset date based on initial slider value var offsetDate = defaultSliderValue ? d3.timeDay.offset(d3.timeMonth.offset((new Date(datePlusOneMonth.getFullYear(), datePlusOneMonth.getMonth() - defaultSliderValue)), 1), -1) : min // set x domain and re-render xAxis x.domain([offsetDate, datePlusOneMonth]); g.select('.x.axis').call(xMonthAxis); var filteredData = data.filter(function(d) { return d.date >= offsetDate; }); barWidth = (width - margin.right - margin.left) / (filteredData.length + barPad); // the bars g.append("g").classed('bars', true) .selectAll("g") .data(d3.stack().keys(keys)(filteredData)) .enter().append("g") .attr('class', function(d) { return d.key; }) .attr("fill", function(d) { return z(d.key); }) .selectAll("rect") .data(function(d) { return d; }) .enter() .append("rect") .attr("x", function(d) { return x(d.data.date); }) .attr("y", function(d) { return y(d[1]); }) .attr("height", function(d) { return y(d[0]) - y(d[1]); }) .attr("width", barWidth) .on("mousemove", function(d) { //Get this bar's x/y values, then augment for the tooltip var xPosition = parseFloat(d3.mouse(this)[0]) + 88; var yPosition = parseFloat(d3.mouse(this)[1]) + 50; var value = d.data[d3.select(this.parentNode).attr('class')]; // differentiating between col1 and col2 values var totalCount = d.data["total"]; var valuePercent = value / totalCount; var valueClass = d3.select(this.parentNode).attr('class').replace("col_1", "Column 1").replace("col_2", "Column 2"); //Update the tooltip position and value d3.select("#tooltip") .style("left", xPosition + "px") .style("top", yPosition + "px") d3.select("#tooltip") .select("#count") .text(formatNum(value)); // return the value d3.select("#tooltip") .select("#totalCount") .text(formatNum(totalCount)); // return the value d3.select("#tooltip") .select("#percent") .text((valuePercent * 100).toFixed(1) + "%"); // return the value d3.select("#tooltip") .select("#month") .text(d3.timeFormat("%B %Y")(d.data.date)); // return the value d3.select("#tooltip") .select("#sessionLabel") .text(valueClass); // return the class //Show the tooltip d3.select("#tooltip").classed("hidden", false); }) .on("mouseout", function() { //Hide the tooltip d3.select("#tooltip").classed("hidden", true); }); g.selectAll("bars") .attr("transform", "translate(0,300)"); const firstDataYear = x.domain()[0]; if (firstDataYear.getMonth() == 11) { // When .getmonth() == 11, this shows two years overlapping with each other, making the label look ugly const firstDataYearOffset = d3.timeDay.offset(firstDataYear, 1); var tickValues = x.ticks().filter(function(d) { return !d.getMonth() }); if (tickValues.length && firstDataYearOffset.getFullYear() !== tickValues[1].getFullYear()) { tickValues = [firstDataYearOffset].concat(tickValues); } else { tickValues = [firstDataYearOffset]; } } else { var tickValues = x.ticks().filter(function(d) { return !d.getMonth() }); if (tickValues.length && firstDataYear.getFullYear() !== tickValues[0].getFullYear()) { tickValues = [firstDataYear].concat(tickValues); } else { tickValues = [firstDataYear]; } } xYearAxis.tickValues(tickValues); var yearAxis = g.append("g") .attr("class", "yearaxis axis") .attr("transform", "translate(0," + (height + 25) + ")") .call(xYearAxis); var valueAxis = g.append("g") .attr("class", "y axis grid") .call(yAxis); monthAxis.selectAll("g").select("text") .attr("transform", "translate(" + barWidth / 2 + ",0)"); var options = d3.keys(data[0]).filter(function(key) { return key !== "date"; }).reverse(); var legend = svg.selectAll(".legend") .data(options.slice().filter(function(type) { return type != "total" })) .enter().append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); legend.append("rect") .attr("x", width - 18) .attr("width", 18) .attr("height", 18) .attr('class', function(d) { return d; }) .style("fill", z) .on("mouseover", function(d) { if (d == 'col_2') { d3.selectAll(".col_2").style("fill", '#008394'); } if (d == 'col_1') { d3.selectAll(".col_1").style("fill", '#80061b'); }; }) .on("mouseout", function() { d3.selectAll(".col_2").style("fill", col_2_col); d3.selectAll(".col_1").style("fill", col_1_col); }); function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } legend.append("text") .attr("x", width - 24) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "end") .text(function(d) { return capitalizeFirstLetter(d.replace("col_1", "Column 1").replace("col_2", "Column 2")); }) .on("mouseover", function(d) { if (d == 'col_2') { d3.selectAll(".col_2").style("fill", '#008394'); } if (d == 'col_1') { d3.selectAll(".col_1").style("fill", '#80061b'); }; }) .on("mouseout", function() { d3.selectAll(".col_2").style("fill", col_2_col); d3.selectAll(".col_1").style("fill", col_1_col); });; // Initialize jQuery slider $('div#month-slider').slider({ min: 1, max: 25, value: defaultSliderValue, create: function() { // add value to the handle on slider creation $(this).find('.ui-slider-handle').html($(this).slider("value")); }, slide: function(e, ui) { // change values on slider handle and label based on slider value $(e.target).find('.ui-slider-handle').html(ui.value); // calculate offset date based on slider value var offsetDate = ui.value ? d3.timeDay.offset(d3.timeMonth.offset((new Date(datePlusOneMonth.getFullYear(), datePlusOneMonth.getMonth() - ui.value)), 1), -1) : min // set x domain and re-render xAxis x.domain([offsetDate, datePlusOneMonth]); g.select('.x.axis').call(xMonthAxis); const firstDataYear = x.domain()[0]; if (firstDataYear.getMonth() == 11) { // When .getmonth() == 11, this shows two years overlapping with each other, making the label look ugly const firstDataYearOffset = d3.timeDay.offset(firstDataYear, 1); var tickValues = x.ticks().filter(function(d) { return !d.getMonth() }); if (tickValues.length == 2 && firstDataYearOffset.getFullYear() !== tickValues[1].getFullYear()) { tickValues = [firstDataYearOffset].concat(tickValues); } else { tickValues = [firstDataYearOffset]; } } else { var tickValues = x.ticks().filter(function(d) { return !d.getMonth() }); if (tickValues.length && firstDataYear.getFullYear() !== tickValues[0].getFullYear()) { tickValues = [firstDataYear].concat(tickValues); } else { tickValues = [firstDataYear]; } } xYearAxis.tickValues(tickValues); g.select('.yearaxis.axis').call(xYearAxis); // calculate filtered data based on new offset date, set y axis domain and re-render y axis var filteredData = data.filter(function(d) { return d.date >= offsetDate; }); y.domain([0, d3.max(filteredData, function(d) { return d.total; })]).nice(); g.select('.y.axis').transition().duration(200).call(yAxis); // re-render the bars based on new filtered data // the bars var bars = g.select("g.bars") .selectAll("g") .data(d3.stack().keys(keys)(filteredData)); var barRects = bars.enter().append("g").merge(bars) .attr('class', function(d) { return d.key; }) .attr("fill", function(d) { return z(d.key); }) .selectAll("rect") .data(function(d) { return d; }); barRects.exit().remove(); barRects.enter() .append("rect"); barWidth = (width - margin.right - margin.left) / (filteredData.length + barPad); monthAxis.selectAll("g").select("text") .attr("transform", "translate(" + barWidth / 2 + ",0)"); g.select("g.bars").selectAll('g rect') .attr("x", function(d) { return x(d.data.date); }) .attr("y", function(d) { return y(d[1]); }) .attr("height", function(d) { return y(d[0]) - y(d[1]); }) .attr("width", barWidth) .on("mousemove", function(d) { //Get this bar's x/y values, then augment for the tooltip var xPosition = parseFloat(d3.mouse(this)[0]) + 88; var yPosition = parseFloat(d3.mouse(this)[1]) + 50; var value = d.data[d3.select(this.parentNode).attr('class')]; // differentiating between col1 and col2 values var totalCount = d.data["total"]; var valuePercent = value / totalCount; var valueClass = d3.select(this.parentNode).attr('class').replace("col_1", "Column 1").replace("col_2", "Column 2"); //Update the tooltip position and value d3.select("#tooltip") .style("left", xPosition + "px") .style("top", yPosition + "px") d3.select("#tooltip") .select("#count") .text(formatNum(value)); // return the value d3.select("#tooltip") .select("#totalCount") .text(formatNum(totalCount)); // return the value d3.select("#tooltip") .select("#percent") .text((valuePercent * 100).toFixed(1) + "%"); // return the value d3.select("#tooltip") .select("#month") .text(d3.timeFormat("%B %Y")(d.data.date)); // return the value d3.select("#tooltip") .select("#sessionLabel") .text(valueClass); // return the class //Show the tooltip d3.select("#tooltip").classed("hidden", false); }) .on("mouseout", function() { //Hide the tooltip d3.select("#tooltip").classed("hidden", true); }); } }); g.append("text") .attr("class", "title") .attr("x", (width / 2)) .attr("y", 0 - (margin.top / 2)) .attr("text-anchor", "middle") .text("Title"); 
 #tooltip { position: absolute; width: 290px; z-index: 2; height: auto; padding: 10px; background-color: white; -webkit-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; -webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); -moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); pointer-events: none; } .legend { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 60%; } #tooltip.hidden { display: none; } #tooltip p { margin: 0; font-family: sans-serif; font-size: 16px; line-height: 20px; } g[class="col_1"] rect:hover { fill: #80061b; } g[class="col_2"] rect:hover { fill: #008394; } div.slider-container { margin: 20px 20px 20px 80px; } div#month-slider { width: 50%; margin: 0px 0px 0px 330px; background: #e3eff4; } div#month-slider .ui-slider .ui-slider-handle { width: 25%; } div#month-slider .ui-slider-handle { text-align: center; } .title { font-size: 30px; font-weight: bold; } .grid line { stroke: lightgrey; stroke-opacity: 0.7; shape-rendering: crispEdges; } .grid path { stroke-width: 0; pointer-events: none; } 
 <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <script src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js" integrity="sha256-eGE6blurk5sHj+rmkfsGYeKyZx3M4bG+ZlFyA7Kns7E=" crossorigin="anonymous"></script> <script src="https://d3js.org/d3.v4.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.7.0/d3-legend.min.js"></script> <body> <div id="tooltip" class="hidden"> <p><strong>Month: </strong><span id="month"></span> <p> <p><strong><span id="sessionLabel"></span>: </strong><span id="count"></span> (<span id="percent"></span>)</p> <p><strong>Total: </strong><span id="totalCount"></span></p> </div> <div class="slider-container" style='inline-block;'> <span style='margin-left:6em;display:inline-block;position:relative;top:15px;'><strong>Number of Months Displayed:</strong></span> <div id="month-slider" style='inline-block;'></div> </div> 

我希望標題位於滑塊上方。 我之所以無法解決問題,是因為滑塊位於與svg元素完全分開的div 因此,在這里最有意義的是將帶有class slider-containerdiv插入svg元素。 如何才能做到這一點?

這是您的選擇:

  • 使用forigenObject svg節點插入您的html滑塊, 但是在IE中forigenObject不支持此功能。
  • 從您的svg刪除標題,使其成為html。
  • 這里創建一個svg滑塊。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM