javascript - 将鼠标悬停在堆积条形图中的线段上时将工具提示与鼠标移动对齐 [Qlik Sense Extension]
问题描述
我正在使用 Qlik Sense Cloud,并且我已经使用 d3.js v4 框架成功创建了堆积条形图。图表如下所示:
如您所见,工具提示未正确放置在 USA 的蓝色部分(错误放置在 Japan-Nordic 上方的空白区域)。如果您想自己测试代码,我建议使用此处的zip 文件夹并将其上传到您工作的 Qlik Sense 版本。我还包含了一个 qvf 文件。我确定我的问题在于 Qlik Sense 窗口,因为在下面附加的 jsfiddle 窗口中测试相同的代码对我有用。但它不能按预期在 Qlik Sense 上运行。
我还在 Qlik Sense 社区中上传了一个问题,但我还没有答案。
具体来说,我使用以下代码来放置我的工具提示:
```javascript
.on("mousemove", function(d) {
var xPosition = d3.event.pageX;
var yPosition = d3.event.pageY;
toolTip.style("left", xPosition + 10 + "px");
toolTip.style("top", yPosition - 25 + "px");
toolTip.style("position", "absolute");
toolTip.style("display", "inline-block");
tooltip.html(...)
}
```
data=[{dValues: "Germany", m1Values: 3323936.920000017, m2Values: 1469934.4999999946},
{dValues: "Japan", m1Values: 11847615.030000022, m2Values: 4860290.499999991},
{dValues: "Nordic", m1Values: 10382965.910000034, m2Values: 4289934.389999997},
{dValues: "Spain", m1Values: 3449601.7199999965, m2Values: 1594701.149999997},
{dValues: "UK", m1Values: 28157182.22999989, m2Values: 12590207.999999987},
{dValues: "USA", m1Values: 47691372.99999974, m2Values: 18448120.5719999}]
var quarters = data.map(function(d) { return d.dValues; })
//console.log('Quarters: ', quarters);
var layers = d3.stack().keys(["m1Values", "m2Values", "m3Values"]).order(d3.stackOrderNone).offset(d3.stackOffsetNone)(data);
//console.log('Layers: ', layers);
var max = d3.max(layers[layers.length-1], function(d) { return d[1]; });
// helper Function to round the displayed numbers
var roundNumber = function roundNumber(num, noPrecision){
//check if the string passed is number or contains formatting like 13%
if (/^[0-9.]+$/.test(num)) {
num = !noPrecision ? parseFloat(num).toFixed(2) : Math.round(num);
if (num >= 1000 && num < 1000000) {
num = !noPrecision ? parseFloat(num / 1000).toFixed(2) : Math.round(num / 1000);
if (/\.00$/.test(num)) {
num = num.replace(/\.00$/, ''); // Remove .00
}
num += 'K'; // Add the abbreviation
} else if (num >= 1000000 && num < 1000000000) {
num = !noPrecision ? parseFloat(num / 1000000).toFixed(2) : Math.round(num / 1000000);
if (/\.00$/.test(num)) {
num = num.replace(/\.00$/, ''); // Remove .00
}
num += 'M'; // Add the abbreviation
} else if (num >= 1000000000) {
num = !noPrecision ? parseFloat(num / 1000000000).toFixed(2) : Math.round(num / 1000000000);
if (/\.00$/.test(num)) {
num = num.replace(/\.00$/, ''); // Remove .00
}
num += 'T'; // Add the abbreviation
}
}
return num;
};
// Step 1: set the dimensions and margins of the graph
var margin = { top: 20, right: 20, bottom: 50, left: 60 }; //adjust left margin to show how y-axis +20 in bottom and left for X,Y axis titles
var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// Step 2: set the ranges for x, y axis
var x = d3.scaleBand()
.range([0, width])
.padding(0.3) //padding will help
var y = d3.scaleLinear()
.range([height, 0]);
color = null;
color = d3.scaleOrdinal().range(["#98abc5", "#8a89a6", "#7b6888"]);
//Step 4: Set color domains
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "dValues"; }));
//Step 5: Create the dataset as needed for the stacked barchart
data.forEach(function(d) {
var y0 = 0;
d.values = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
d.total = d.values[d.values.length - 1].y1;
});
//step 6: Set rest domains
y.domain([0, d3.max(data, function(d) { return d.total; })]);
x.domain(quarters);
//-----------------------------------------------------------------------------
// Build the svg chart
var svg = d3.select("body").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 + ")");
// Create Parent Group layering
svg.append("g").attr("id", "grid");
//Add x axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add the y Axis
svg.append("g")
.attr("transform", "translate(0,0)")
.call(d3.axisLeft(y).tickFormat(d3.format(".2s")));
//toolTip
var toolTip = d3.select("body").append("div")
.attr("class", "toolTip")
.html("toolTip")
.style("display", "none");
var project_stackedbar = svg.selectAll(".project_stackedbar")
.data(data.reverse())
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + (x(d.dValues)) + ",0)"; });
var bar_environment = project_stackedbar.selectAll("rect")
.data(function(d) { return d.values; })
.enter();
bar_environment.append("rect")
.attr("class", "rect-svg")
.attr("x", d => x(d.dValues))
.attr("y", function(d) {
return y(d.y1);
})
.attr("width", x.bandwidth() - 1)
.attr("height", function(d){
return y(d.y0) - y(d.y1);
})
.style("fill", function(d) {
return color(d.name);
});
bar_environment.append("text")
.attr("class", "text-svg")
.attr("y", function(d) {
return y(d.y1)+(y(d.y0) - y(d.y1))/2;
})
.attr("x", function(d){
return x.bandwidth()/2;
})
.attr("text-anchor","middle")
.attr("font-size","12px")
.attr("font-family","Helvetica")
.style("fill", "#000000")
.text(function(d) {
return roundNumber(d.y1 - d.y0);
});
project_stackedbar.on("mouseover", function() { toolTip.style("display", null); })
.on("mouseout", function() { toolTip.style("display", "none"); })
.on("mousemove", function(d) {
// var xPosition = d3.mouse(this)[0];
// var yPosition = d3.mouse(this)[1];
var xPosition = d3.event.pageX;
var yPosition = d3.event.pageY;
// toolTip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
toolTip.style("left", xPosition + 10 + "px");
toolTip.style("top", yPosition - 25 + "px");
toolTip.style("position", "absolute");
toolTip.style("display", "inline-block");
var elements = document.querySelectorAll(':hover');
l = elements.length
l = l-1
element = elements[l].__data__
value = element.y1 - element.y0
if(element.name === "m1Values"){
toolTip.html("Region" + ": " + (d.dValues) +
"<br>"+ "Sum(Sales)" + ": " + roundNumber(value));
} else if(element.name ==="m2Values"){
toolTip.html("Region" + ": " + (d.dValues) +
"<br>"+ "Sum(Margin)" + ": " + roundNumber(value));
}else{
toolTip.html("Region" + ": " + (d.dValues) +
"<br>"+ "Sum(GrossSales)" + ": " + roundNumber(value));
}
});
var totalLabels = svg.append('g').attr('class', 'totals');
totalLabels.selectAll('.total')
.data(data)
.enter().append('text')
.attr('class', 'total')
.attr("x", function(d) { return x(d.dValues) + x.bandwidth()/2; })
.attr("y", function(d) {
// Retrieve the horizontal coordinates based on total (stored as d.value)
// Add pixel offset so labels don't stick to end of stacked bars
return y(d.total) - 5; })
.attr("text-anchor","middle")
.attr("font-size","12px")
.attr("font-family","Helvetica")
.style("fill", "#000000")
.text(function(d) {
// Inject total as text content (stored as d.value)
return roundNumber(d.total);
});
var legend = svg.append("g")
.attr("font-family", "Helvetica")
.attr("font-size", 10)
.attr("text-anchor", "end")
.selectAll("g")
.data(["Sum(Sales)", "Sum(Margin)", "Sum(GrossSales)"])
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 19)
.attr("width", 19)
.attr("height", 19)
.attr("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9.5)
.attr("dy", "0.32em")
.text(function(d) { return d; });
console.log("Stacked BarChart completed");
/* .bar {
fill: steelblue; Not needed anymore after adding the color picker
} */
div.toolTip{
position: absolute; /*we need the tooltip to follow the mouse on the screen */
background-color: white;
opacity: 0.9;
border: 1px solid #c9c9c9;
padding: 10px;
}
.gridlines line {
stroke: lightgrey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.gridlines path {
stroke-width: 0;
}
body {
font-family: 'Open Sans', sans-serif;
}
<script src="https://d3js.org/d3.v4.min.js"></script>https://stackoverflow.com/questions/ask#
解决方案
推荐阅读
- c# - 在 docker 上运行的 postgresql 的连接字符串
- java - 单元测试android:调用另一个函数返回和使用时如何返回函数不为null
- python - 我有一个 Employee 类,我想返回一个“名称”列表
- django - 如何通过模型获取过滤器类或视图集类?
- c++ - Raspberry Pi 零 - 变成虚拟鼠标在 Windows 10 build 1809 上无法正常工作(光标快速回到左上角)
- ruby-on-rails - 迁移未决错误,而一切都是最新的
- arrays - 每当路由调用时,在 Node JS 中将数组从一个文件传输到另一个文件
- java - 具有空日期或值的 QueryBuilders rangeQuery
- javascript - ngx-bootstrap 下拉菜单 DOM 未在初始化时呈现
- c# - 删除元组列表中的重复值和求和值