From 2c1f7647738ea3aef3de53de8c758d96a53b30d8 Mon Sep 17 00:00:00 2001 From: "John M. Horan" <“johnmhoran@gmail.com”> Date: Mon, 7 Aug 2017 10:19:57 -0700 Subject: [PATCH 1/5] Set max width for bar chart labels #141 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Changes: * Bar chart label text is limited to 50 characters (plus “. . .” for those strings that exceed 50 and are therefore abbreviated). Particularly noticeable (at least on “zlib-1.2.11” test scan) for the “Copyright Statements” selection. * Tooltip is displayed on mousing over the bar for all bar chart selections. * Tooltip displays the label text plus the count in parentheses. * Replace '<' with '<' before calling tooltip -- for some reason the open angle-bracket interrupts the tooltip display (the close angle-bracket seems to display OK as is). * Chart dropdown no longer has a visible focus outline/border after a selection is made. * Open issues: * Adding a tooltip for the bar chart labels would be helpful since on some display scales, the bar chart bar for some items is small and triggering the tooltip requires precise placement. (I researched and experimented extensively but could not figure out how to accomplish this.) * The “Copyright Authors” selection is displayed on launch but not shown as selected in the dropdown’s default display. (This behavior existed before adding the tooltip.) * The margin/whitespace between the top of the vertical axis and the top-most item increases as the number of displayed items increases. Similar behavior for the bottom of the axis. This is most pronounced (on the “zlib-1.2.11” test scan) for the “Copyright Statements” selection (73 items displayed). (This behavior existed before adding the tooltip.) Signed-off-by: John M. Horan --- assets/css/main.css | 19 +++++++++++++++++++ assets/js/barChart.js | 30 +++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/assets/css/main.css b/assets/css/main.css index 401b59f1..3a8a853d 100644 --- a/assets/css/main.css +++ b/assets/css/main.css @@ -343,3 +343,22 @@ html, body { stroke: #000; shape-rendering: crispEdges; } + +/* Remove focus from Bar Chart dropdown after selection is made. */ +.select2-selection:focus { + outline: none; +} + +/* Tooltip for Bar Chart */ + .toolTip { + position: absolute; + display: none; + min-width: 80px; + height: auto; + background: #333333; + border: 1px solid #000000; + border-radius: 4px; + padding: 14px; + text-align: center; + color: #ffffff; +} \ No newline at end of file diff --git a/assets/js/barChart.js b/assets/js/barChart.js index 3af9ba7b..6911a912 100644 --- a/assets/js/barChart.js +++ b/assets/js/barChart.js @@ -50,7 +50,7 @@ class BarChart { // Create scaling for y that converts formattedData names to pixels let yScale = d3.scale.ordinal() - .domain(formattedData.map(function(d) {return d.name; })) + .domain(formattedData.map(function(d) {return d.trimName; })) .rangeRoundBands([0, chartHeight], 0.1 /* white space percentage */); // Creates a d3 axis given a scale (takes care of tick marks and labels) @@ -69,11 +69,24 @@ class BarChart { .enter().append('g'); this.rects = bars.append('rect') - .attr('y', function(d) { return yScale(d.name); }) - .attr('height', yScale.rangeBand()); + .attr('y', function(d) { return yScale(d.trimName); }) + .attr('height', yScale.rangeBand()) + .on("mouseover", function (d) { + tooltip + .style("left", d3.event.pageX - 50 + "px") + .style("top", d3.event.pageY - 70 + "px") + .style("display", "inline-block") + .html((d.name.replace('<', '<') + ' (' + d.val + ')')); + }) + .on("mouseout", function (d) { tooltip.style("display", "none"); }); + + // Clear tooltip div created when inadvertently triggered during dropdown selection. + $( ".toolTip" ).remove(); + + let tooltip = d3.select("body").append("div").attr("class", "toolTip"); this.texts = bars.append('text') - .attr('y', function(d) { return yScale(d.name); }) + .attr('y', function(d) { return yScale(d.trimName); }) .attr('dy', '1.2em') .text(function(d){ return '(' + d.val + ')'; }) .style('text-anchor', 'start'); @@ -121,7 +134,7 @@ class BarChart { // Returns the pixel width of the string with the longest length maxNameWidth(data) { - let names = data.map(function(d) { return d.name; }); + let names = data.map(function(d) { return d.trimName; }); let maxStr = ''; $.each(names, function(i, name) { @@ -149,8 +162,15 @@ class BarChart { // Transform license count into array of objects with license name & count let chartData = $.map(count, function(val, key) { + let trimName = ""; + if (key.length > 50) { + trimName = key.substring(0, 50) + ' . . .' + } else { + trimName = key; + } return { name: key, + trimName: trimName, val: val }; }); From b16ebec6dc5b43b816a952f8c51e98d1f51b9ada Mon Sep 17 00:00:00 2001 From: "John M. Horan" <“johnmhoran@gmail.com”> Date: Mon, 7 Aug 2017 14:42:30 -0700 Subject: [PATCH 2/5] Modify tooltip to move with cursor #141 Signed-off-by: John M. Horan --- assets/js/barChart.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/js/barChart.js b/assets/js/barChart.js index 6911a912..05c68cac 100644 --- a/assets/js/barChart.js +++ b/assets/js/barChart.js @@ -71,7 +71,8 @@ class BarChart { this.rects = bars.append('rect') .attr('y', function(d) { return yScale(d.trimName); }) .attr('height', yScale.rangeBand()) - .on("mouseover", function (d) { + .on("mouseover", function (d) { tooltip.style("display", "inline-block"); }) + .on("mousemove", function (d) { tooltip .style("left", d3.event.pageX - 50 + "px") .style("top", d3.event.pageY - 70 + "px") From b499a6265d821b1ee3a8b28fe31cff3bb8b92150 Mon Sep 17 00:00:00 2001 From: "John M. Horan" <“johnmhoran@gmail.com”> Date: Wed, 9 Aug 2017 14:56:26 -0700 Subject: [PATCH 3/5] Add tooltips to y-axis labels #141 * Bar chart labels now have tooltips with same content as corresponding bars. * Changed from truncated name to full name as appropriate. Signed-off-by: John M. Horan --- assets/css/main.css | 2 +- assets/js/barChart.js | 36 +++++++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/assets/css/main.css b/assets/css/main.css index 962c4751..7547a9d1 100644 --- a/assets/css/main.css +++ b/assets/css/main.css @@ -355,7 +355,7 @@ div.dataTables_scrollHead th:first-child { } /* Tooltip for Bar Chart */ - .toolTip { +.toolTip { position: absolute; display: none; min-width: 80px; diff --git a/assets/js/barChart.js b/assets/js/barChart.js index 05c68cac..e3836c3d 100644 --- a/assets/js/barChart.js +++ b/assets/js/barChart.js @@ -50,7 +50,7 @@ class BarChart { // Create scaling for y that converts formattedData names to pixels let yScale = d3.scale.ordinal() - .domain(formattedData.map(function(d) {return d.trimName; })) + .domain(formattedData.map(function(d) {return d.name; })) .rangeRoundBands([0, chartHeight], 0.1 /* white space percentage */); // Creates a d3 axis given a scale (takes care of tick marks and labels) @@ -61,6 +61,10 @@ class BarChart { // Creates a d3 axis given a scale (takes care of tick marks and labels) let yAxis = d3.svg.axis() .scale(yScale) + // Limit label length to 50 characters plus ellipses. + .tickFormat(function(d) { + return d.substring(0, 50) + (d.length > 50 ? " ..." : ""); + }) .orient('left'); // Creates a graphic tag () for each bar in the chart @@ -69,8 +73,9 @@ class BarChart { .enter().append('g'); this.rects = bars.append('rect') - .attr('y', function(d) { return yScale(d.trimName); }) + .attr('y', function(d) { return yScale(d.name); }) .attr('height', yScale.rangeBand()) + // Add a tooltip to the bar. .on("mouseover", function (d) { tooltip.style("display", "inline-block"); }) .on("mousemove", function (d) { tooltip @@ -87,9 +92,9 @@ class BarChart { let tooltip = d3.select("body").append("div").attr("class", "toolTip"); this.texts = bars.append('text') - .attr('y', function(d) { return yScale(d.trimName); }) + .attr('y', function (d) { return yScale(d.name); }) .attr('dy', '1.2em') - .text(function(d){ return '(' + d.val + ')'; }) + .text(function (d) { return '(' + d.val + ')'; }) .style('text-anchor', 'start'); // Adds the y-axis to the chart if data exists @@ -99,6 +104,23 @@ class BarChart { .call(yAxis); } + // Add a tooltip to the y-axis labels. + let summaryData = formattedData; + chart.selectAll(".y.axis .tick") + .on("mouseover", function (d) { tooltip.style("display", "inline-block"); }) + .on("mousemove", function (d) { + let id = d; + let displayValue = ''; + let result = $.grep(summaryData, function (e) { return e.name === id; }); + displayValue = (result.length === 1 ? ' (' + result[0].val + ')' : ''); + tooltip + .style("left", d3.event.pageX - 50 + "px") + .style("top", d3.event.pageY - 70 + "px") + .style("display", "inline-block") + .html((d.replace('<', '<') + displayValue)); + }) + .on("mouseout", function (d) { tooltip.style("display", "none"); }); + this.draw(); } @@ -164,11 +186,7 @@ class BarChart { // Transform license count into array of objects with license name & count let chartData = $.map(count, function(val, key) { let trimName = ""; - if (key.length > 50) { - trimName = key.substring(0, 50) + ' . . .' - } else { - trimName = key; - } + trimName = key.substring(0, 50) + (key.length > 50 ? " ..." : ""); return { name: key, trimName: trimName, From a74d740315f41edf5aad4ac2b610694639b4cdc8 Mon Sep 17 00:00:00 2001 From: "John M. Horan" <“johnmhoran@gmail.com”> Date: Wed, 16 Aug 2017 10:47:27 -0700 Subject: [PATCH 4/5] Refactor and clean code #141 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * One note: retained this line of code because it’s needed, at least on Windows, but for some reason Jillian has not been able to reproduce on Mac: $( ".toolTip" ).remove(); Signed-off-by: John M. Horan --- assets/js/barChart.js | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/assets/js/barChart.js b/assets/js/barChart.js index e3836c3d..11149d56 100644 --- a/assets/js/barChart.js +++ b/assets/js/barChart.js @@ -63,7 +63,7 @@ class BarChart { .scale(yScale) // Limit label length to 50 characters plus ellipses. .tickFormat(function(d) { - return d.substring(0, 50) + (d.length > 50 ? " ..." : ""); + return BarChart.trimName(d); }) .orient('left'); @@ -72,6 +72,11 @@ class BarChart { .data(formattedData) .enter().append('g'); + // Clear tooltip div created when inadvertently triggered during dropdown selection. + $( ".toolTip" ).remove(); + + let tooltip = d3.select("body").append("div").attr("class", "toolTip"); + this.rects = bars.append('rect') .attr('y', function(d) { return yScale(d.name); }) .attr('height', yScale.rangeBand()) @@ -81,16 +86,10 @@ class BarChart { tooltip .style("left", d3.event.pageX - 50 + "px") .style("top", d3.event.pageY - 70 + "px") - .style("display", "inline-block") - .html((d.name.replace('<', '<') + ' (' + d.val + ')')); + .text((d.name + ' (' + d.val + ')')); }) .on("mouseout", function (d) { tooltip.style("display", "none"); }); - // Clear tooltip div created when inadvertently triggered during dropdown selection. - $( ".toolTip" ).remove(); - - let tooltip = d3.select("body").append("div").attr("class", "toolTip"); - this.texts = bars.append('text') .attr('y', function (d) { return yScale(d.name); }) .attr('dy', '1.2em') @@ -105,25 +104,25 @@ class BarChart { } // Add a tooltip to the y-axis labels. - let summaryData = formattedData; chart.selectAll(".y.axis .tick") .on("mouseover", function (d) { tooltip.style("display", "inline-block"); }) .on("mousemove", function (d) { - let id = d; - let displayValue = ''; - let result = $.grep(summaryData, function (e) { return e.name === id; }); - displayValue = (result.length === 1 ? ' (' + result[0].val + ')' : ''); + let result = $.grep(formattedData, function (e) { return e.name === d; }); + let displayValue = ' (' + result[0].val + ')'; tooltip .style("left", d3.event.pageX - 50 + "px") .style("top", d3.event.pageY - 70 + "px") - .style("display", "inline-block") - .html((d.replace('<', '<') + displayValue)); + .text((d + displayValue)); }) .on("mouseout", function (d) { tooltip.style("display", "none"); }); this.draw(); } + static trimName(name) { + return name.substring(0, 50) + (name.length > 50 ? " ..." : ""); + } + // Redraws chart and sets width based on available chart width. // User needs to call this function whenever the width of the chart changes. draw() { @@ -157,7 +156,7 @@ class BarChart { // Returns the pixel width of the string with the longest length maxNameWidth(data) { - let names = data.map(function(d) { return d.trimName; }); + let names = data.map(function(d) { return d.trimmedName; }); let maxStr = ''; $.each(names, function(i, name) { @@ -185,11 +184,10 @@ class BarChart { // Transform license count into array of objects with license name & count let chartData = $.map(count, function(val, key) { - let trimName = ""; - trimName = key.substring(0, 50) + (key.length > 50 ? " ..." : ""); + let trimmedName = BarChart.trimName(key); return { name: key, - trimName: trimName, + trimmedName: trimmedName, val: val }; }); From 5bae436826ed949e0e3e600f736187986b738619 Mon Sep 17 00:00:00 2001 From: "John M. Horan" <“johnmhoran@gmail.com”> Date: Thu, 17 Aug 2017 11:12:22 -0700 Subject: [PATCH 5/5] Minor cleanup #141 Signed-off-by: John M. Horan --- assets/js/barChart.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/assets/js/barChart.js b/assets/js/barChart.js index 11149d56..170ab406 100644 --- a/assets/js/barChart.js +++ b/assets/js/barChart.js @@ -62,9 +62,7 @@ class BarChart { let yAxis = d3.svg.axis() .scale(yScale) // Limit label length to 50 characters plus ellipses. - .tickFormat(function(d) { - return BarChart.trimName(d); - }) + .tickFormat(BarChart.trimName) .orient('left'); // Creates a graphic tag () for each bar in the chart @@ -184,10 +182,9 @@ class BarChart { // Transform license count into array of objects with license name & count let chartData = $.map(count, function(val, key) { - let trimmedName = BarChart.trimName(key); return { name: key, - trimmedName: trimmedName, + trimmedName: BarChart.trimName(key), val: val }; });