Skip to content

Commit 0e37770

Browse files
lastboyArik Levin
andauthored
Fix the tootip and click mouse positioning over the paths (#5)
Co-authored-by: Arik Levin <arik.levin@aquaseq.com>
1 parent d335b61 commit 0e37770

File tree

5 files changed

+244
-135
lines changed

5 files changed

+244
-135
lines changed

dist/js/funnel-graph.js

Lines changed: 116 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -5353,6 +5353,7 @@ var getInfoSvgGroup = function getInfoSvgGroup(id, margin) {
53535353
if (group.empty()) {
53545354
group = svg.append('g').attr('id', groupId);
53555355
if (margin) {
5356+
// TODO: evaluate - delete if not in use
53565357
// group.attr('transform', `translate(${margin.left}, 0)`);
53575358
}
53585359
}
@@ -5448,21 +5449,28 @@ var mouseInfoHandler = function mouseInfoHandler(_ref5) {
54485449
metadata = _ref5.metadata,
54495450
tooltip = _ref5.tooltip;
54505451
return function (event) {
5451-
var width = context.getWidth(false);
5452-
var height = context.getHeight(false);
5452+
var _context$getDimension = context.getDimensions({
5453+
context: context,
5454+
margin: false
5455+
}),
5456+
width = _context$getDimension.width,
5457+
height = _context$getDimension.height;
54535458
var isVertical = context.isVertical();
5459+
updateLinePositions({
5460+
context: context
5461+
});
54545462
var linePositions = context.getLinePositions();
5463+
5464+
// Determine the area between the lines
54555465
var clickPoint = {
54565466
x: event.offsetX,
54575467
y: event.offsetY
54585468
};
5459-
5460-
// Determine the area between the lines
54615469
var areaIndex = linePositions.findIndex(function (pos, i) {
54625470
if (!isVertical) {
5463-
return clickPoint.x > pos && clickPoint.x < (linePositions[i + 1] || width);
5471+
return clickPoint.x >= pos && clickPoint.x <= (linePositions[i + 1] || width);
54645472
} else {
5465-
return clickPoint.y > pos && clickPoint.y < (linePositions[i + 1] || height);
5473+
return clickPoint.y >= pos && clickPoint.y <= (linePositions[i + 1] || height);
54665474
}
54675475
});
54685476

@@ -5481,7 +5489,7 @@ var mouseInfoHandler = function mouseInfoHandler(_ref5) {
54815489
sectionIndex: areaIndex
54825490
};
54835491
metadata = _objectSpread(_objectSpread({}, metadata), dataInfoItemForArea);
5484-
if (!tooltip) {
5492+
if (!tooltip && handler) {
54855493
handler(event, metadata);
54865494
}
54875495
return metadata;
@@ -5491,14 +5499,14 @@ var addMouseEventIfNotExists = function addMouseEventIfNotExists(_ref6) {
54915499
var context = _ref6.context;
54925500
return function (pathElement, handler, metadata) {
54935501
var clickEventExists = !!(pathElement !== null && pathElement !== void 0 && pathElement.on('click'));
5494-
if (!clickEventExists) {
5502+
if (!clickEventExists && handler) {
54955503
pathElement === null || pathElement === void 0 || pathElement.on('click', mouseInfoHandler({
54965504
context: context,
54975505
handler: handler,
54985506
metadata: metadata
54995507
}));
55005508
}
5501-
if (!context.showDetails() || !context.showTooltip()) {
5509+
if (!context.showDetails()) {
55025510
pathElement === null || pathElement === void 0 || pathElement.on('mouseover', null);
55035511
pathElement === null || pathElement === void 0 || pathElement.on('mousemove', null);
55045512
pathElement === null || pathElement === void 0 || pathElement.on('mouseout', null);
@@ -5507,6 +5515,7 @@ var addMouseEventIfNotExists = function addMouseEventIfNotExists(_ref6) {
55075515
var overEventExists = !!pathElement.on('mouseover');
55085516
if (!overEventExists) {
55095517
var updateTooltip = function updateTooltip(event) {
5518+
var _this = this;
55105519
var is2d = context.is2d();
55115520
var mouseHandler = mouseInfoHandler({
55125521
context: context,
@@ -5519,20 +5528,47 @@ var addMouseEventIfNotExists = function addMouseEventIfNotExists(_ref6) {
55195528
var tooltipElement = getTooltipElement();
55205529
if (tooltipTimeout) tooltipTimeout.stop();
55215530
tooltipTimeout = (0, _d3Timer.timeout)(function () {
5522-
var label = handlerMetadata.label || "Value";
5523-
label = is2d ? handlerMetadata.subLabel || label : label;
5524-
var tooltipText = "".concat(label, ": ").concat(handlerMetadata.value);
5525-
tooltipElement.style("left", event.offsetX + 10 + "px").style("top", event.offsetY + 10 + "px").text(tooltipText).style("opacity", "1").style("display", "flex");
5531+
var path = (0, _d3Selection.select)(_this);
5532+
if (context.showTooltip() && path && tooltipElement) {
5533+
var coordinates = (0, _d3Selection.pointer)(event, (0, _d3Selection.select)(_this));
5534+
var clickPoint = {
5535+
x: coordinates[0],
5536+
y: coordinates[1]
5537+
};
5538+
var label = handlerMetadata.label || "Value";
5539+
label = is2d ? handlerMetadata.subLabel || label : label;
5540+
var tooltipText = "".concat(label, ": ").concat(handlerMetadata.value);
5541+
tooltipElement
5542+
// TODO: when exceeding the document area - move the tooltip up/down or left/right
5543+
// according to the position (e.g. top /right window exceeded or right)
5544+
.style("left", clickPoint.x + 10 + "px").style("top", clickPoint.y + 10 + "px").text(tooltipText).style("opacity", "1").style("display", "flex");
5545+
}
55265546
}, 500);
5547+
if (event.type === "mouseover") {
5548+
var _pathElement = (0, _d3Selection.select)(this);
5549+
if (_pathElement) {
5550+
var _clickEventExists = !!(_pathElement !== null && _pathElement !== void 0 && _pathElement.on('click'));
5551+
_pathElement.transition().duration(500).attr("stroke-width", '6px');
5552+
if (_clickEventExists) {
5553+
_pathElement.style("cursor", "pointer");
5554+
}
5555+
}
5556+
}
55275557
}
55285558
};
55295559
var tooltipTimeout;
55305560
pathElement.on('mouseover', updateTooltip);
55315561
pathElement.on('mousemove', updateTooltip);
5532-
pathElement.on('mouseout', function () {
5562+
pathElement.on('mouseout', function (event) {
5563+
var pathElement = (0, _d3Selection.select)(event.target);
5564+
if (pathElement) {
5565+
pathElement.transition().duration(500).style("cursor", "pointer").attr("stroke-width", '0');
5566+
}
55335567
if (tooltipTimeout) tooltipTimeout.stop();
55345568
var tooltipElement = getTooltipElement();
5535-
tooltipElement.style("opacity", "0").style("display", "none").text("");
5569+
if (tooltipElement) {
5570+
tooltipElement.style("opacity", "0").style("display", "none").text("");
5571+
}
55365572
});
55375573
}
55385574
};
@@ -5547,8 +5583,6 @@ var removeClickEvent = function removeClickEvent(pathElement) {
55475583
var onEachPathHandler = function onEachPathHandler(_ref7) {
55485584
var context = _ref7.context;
55495585
return function (d, i, nodes) {
5550-
// id, is2d, width, height, isVertical, colors, gradientDirection, callbacks
5551-
55525586
var id = context.getId();
55535587
var is2d = context.is2d();
55545588
var colors = context.getColors();
@@ -5562,14 +5596,12 @@ var onEachPathHandler = function onEachPathHandler(_ref7) {
55625596
} else if (fillMode === 'gradient') {
55635597
applyGradient(id, d3Path, color, i + 1, gradientDirection);
55645598
}
5565-
if (typeof (callbacks === null || callbacks === void 0 ? void 0 : callbacks.click) === 'function') {
5566-
var addMouseHandler = addMouseEventIfNotExists({
5567-
context: context
5568-
});
5569-
addMouseHandler(d3Path, callbacks.click, {
5570-
index: i
5571-
});
5572-
}
5599+
var addMouseHandler = addMouseEventIfNotExists({
5600+
context: context
5601+
});
5602+
addMouseHandler(d3Path, typeof (callbacks === null || callbacks === void 0 ? void 0 : callbacks.click) === 'function' ? callbacks.click : undefined, {
5603+
index: i
5604+
});
55735605
};
55745606
};
55755607

@@ -5617,7 +5649,7 @@ var drawPaths = exports.drawPaths = function drawPaths(_ref9) {
56175649
// paths creation
56185650
var enterPaths = paths.enter().append('path').attr('d', function (d) {
56195651
return d.path;
5620-
}).attr('data-info', getDataInfoHandler).attr('opacity', 0).transition().ease(_d3Ease.easePolyInOut).delay(function (d, i) {
5652+
}).attr('data-info', getDataInfoHandler).attr('opacity', 0).attr("stroke-width", '0').transition().ease(_d3Ease.easePolyInOut).delay(function (d, i) {
56215653
return i * 100;
56225654
}).duration(1000).attr('opacity', 1).each(pathHandler);
56235655

@@ -5626,12 +5658,12 @@ var drawPaths = exports.drawPaths = function drawPaths(_ref9) {
56265658
return i * 100;
56275659
}).duration(1000).attr('d', function (d) {
56285660
return d.path;
5629-
}).attr('data-info', getDataInfoHandler).attr('opacity', 1).each(pathHandler);
5661+
}).attr('data-info', getDataInfoHandler).attr("stroke-width", '0').attr('opacity', 1).each(pathHandler);
56305662

56315663
// Exit and remove old paths
56325664
paths.exit().transition().ease(_d3Ease.easePolyInOut).delay(function (d, i) {
56335665
return i * 100;
5634-
}).duration(1000).attr('opacity', 0).each(function () {
5666+
}).duration(1000).attr('opacity', 0).attr("stroke-width", '0').each(function () {
56355667
var path = (0, _d3Selection.select)(this);
56365668
path.on('end', function () {
56375669
removeClickEvent(path);
@@ -5661,21 +5693,33 @@ var onEachTextHandler = function onEachTextHandler(_ref10) {
56615693
// Function to update line positions
56625694
var updateLinePositions = function updateLinePositions(_ref11) {
56635695
var context = _ref11.context;
5664-
return function (info, vertical, margin, noMarginSpacing) {
5665-
context.setLinePositions(info.map(function (d, i) {
5666-
return noMarginSpacing * (i + 1) + (!vertical ? margin.left : margin.top);
5667-
}));
5668-
};
5696+
var _context$getDimension2 = context.getDimensions({
5697+
context: context,
5698+
margin: false
5699+
}),
5700+
width = _context$getDimension2.width,
5701+
height = _context$getDimension2.height,
5702+
xFactor = _context$getDimension2.xFactor,
5703+
yFactor = _context$getDimension2.yFactor;
5704+
var margin = context.getMargin();
5705+
var info = context.getInfo();
5706+
var vertical = context.isVertical();
5707+
var noMarginHeight = height - margin.top * yFactor - margin.bottom * yFactor;
5708+
var noMarginWidth = width - margin.left * xFactor - margin.right * xFactor;
5709+
var noMarginSpacing = (!vertical ? noMarginWidth : noMarginHeight) / info.length;
5710+
context.setLinePositions(info.map(function (d, i) {
5711+
return noMarginSpacing * (i + 1) + (!vertical ? margin.left * xFactor : margin.top * yFactor);
5712+
}));
56695713
};
56705714

56715715
/**
56725716
* Handle the SVG text display on the graph
56735717
*/
56745718
var drawInfo = exports.drawInfo = function drawInfo(_ref12) {
5675-
var context = _ref12.context,
5676-
info = _ref12.info;
5719+
var context = _ref12.context;
56775720
var id = context.getId();
56785721
var margin = context.getMargin();
5722+
var info = context.getInfo();
56795723
updateSVGGroup(id, margin);
56805724
if (!context.showDetails()) {
56815725
getInfoSvgGroup(id, margin).selectAll('g.label__group').remove();
@@ -5693,9 +5737,6 @@ var drawInfo = exports.drawInfo = function drawInfo(_ref12) {
56935737
var calcTextPos = function calcTextPos(i) {
56945738
return noMarginSpacing * i + (!vertical ? margin.left : margin.top) + noMarginSpacing / textGap;
56955739
};
5696-
var updateLinePositionsHandler = updateLinePositions({
5697-
context: context
5698-
});
56995740
getInfoSvgGroup(id, margin).selectAll('g.label__group').data(info).join(function (enter) {
57005741
return enter.append("g").attr("class", "label__group").each(function (d, i) {
57015742
var x = !vertical ? calcTextPos(i) : margin.text;
@@ -5753,9 +5794,6 @@ var drawInfo = exports.drawInfo = function drawInfo(_ref12) {
57535794
return exit.remove();
57545795
});
57555796

5756-
// Update line positions initially
5757-
updateLinePositionsHandler(info, vertical, margin, noMarginSpacing);
5758-
57595797
// display graph dividers
57605798
var infoCopy = info.slice(0, -1);
57615799
var lines = getInfoSvgGroup(id, margin).selectAll('.divider').data(infoCopy);
@@ -5778,6 +5816,11 @@ var drawInfo = exports.drawInfo = function drawInfo(_ref12) {
57785816

57795817
// Exit selection
57805818
lines.exit().transition().duration(500).attr('stroke-opacity', 0).remove();
5819+
5820+
// Update line positions initially
5821+
updateLinePositions({
5822+
context: context
5823+
});
57815824
} else {
57825825
getInfoSvgGroup(id, margin).selectAll('g.label__group').remove();
57835826
getInfoSvgGroup(id, margin).selectAll('.divider').remove();
@@ -6052,6 +6095,37 @@ var FunnelGraph = /*#__PURE__*/function () {
60526095
var height = margin ? this.margin.top + this.margin.bottom : 0;
60536096
return this.height + height;
60546097
}
6098+
}, {
6099+
key: "getDimensions",
6100+
value: function getDimensions(_ref) {
6101+
var context = _ref.context,
6102+
_ref$margin = _ref.margin,
6103+
margin = _ref$margin === void 0 ? true : _ref$margin;
6104+
var id = context.getId();
6105+
var d3Svg = (0, _d.getRootSvg)(id);
6106+
if (!(d3Svg !== null && d3Svg !== void 0 && d3Svg.node())) {
6107+
return {
6108+
width: context.getWidth(margin),
6109+
height: context.getHeight(margin)
6110+
};
6111+
}
6112+
var boundingRect = d3Svg.node().getBoundingClientRect();
6113+
6114+
// Calculate the scale factors
6115+
var xFactor = boundingRect.width / context.getWidth(true);
6116+
var yFactor = boundingRect.height / context.getHeight(true);
6117+
var width = boundingRect.width;
6118+
var height = boundingRect.height;
6119+
var marginObj = context.getMargin();
6120+
width += margin ? marginObj.left + marginObj.right : 0;
6121+
height += margin ? marginObj.tooltip + marginObj.bottom : 0;
6122+
return {
6123+
width: width,
6124+
height: height,
6125+
xFactor: xFactor,
6126+
yFactor: yFactor
6127+
};
6128+
}
60556129

60566130
/**
60576131
* Get the margin object { top: , right: , bottom: , left: }
@@ -6154,28 +6228,12 @@ var FunnelGraph = /*#__PURE__*/function () {
61546228
}, {
61556229
key: "setLabels",
61566230
value: function setLabels(labels) {
6157-
// if (!options.data) {
6158-
// throw new Error('Data is missing');
6159-
// }
6160-
6161-
// const { data } = options;
6162-
6163-
// if (typeof data.labels === 'undefined') return [];
6164-
61656231
labels = (0, _utils.normalizeArray)(labels);
61666232
this.labels = labels;
61676233
}
61686234
}, {
61696235
key: "setValues",
61706236
value: function setValues(values) {
6171-
// let values = [];
6172-
6173-
// const { data } = options;
6174-
6175-
// if (typeof data === 'object') {
6176-
// values = data.values;
6177-
// }
6178-
61796237
values = (0, _utils.normalizeArray)(values);
61806238
this.values = values;
61816239
}
@@ -6341,10 +6399,8 @@ var FunnelGraph = /*#__PURE__*/function () {
63416399
context: this.getContext(),
63426400
definitions: definitions
63436401
});
6344-
var info = this.getInfo();
63456402
(0, _d.drawInfo)({
6346-
context: this.getContext(),
6347-
info: info
6403+
context: this.getContext()
63486404
});
63496405
}
63506406

dist/js/funnel-graph.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "d3-funnel-graph",
3-
"version": "1.0.6",
3+
"version": "1.0.7",
44
"description": "SVG Funnel Graph Javascript Library",
55
"main": "dist/js/funnel-graph.min.js",
66
"style": "dist/funnel-graph.min.css",

0 commit comments

Comments
 (0)