function mouseover(layer, text, mouse, boundaries, spacing=[20, 20, 20]) { layer.selectAll('*').remove(); let [x, y] = mouse; let [w, h] = boundaries; let mouseoverLayer = layer.append('g').attr('class', 'mouseover') let rect = mouseoverLayer.append('rect'); let rectTitle = mouseoverLayer.append('rect'); let maxLineWidth = 0; text.forEach((line, j) => { let text = mouseoverLayer.append('text').text(line) .attr('class', `mouseover-text mouseover-line-${j}`) .attr('x', 0) .attr('y', 0) .attr('dy', d3.sum(spacing.slice(0, j+1))) maxLineWidth = Math.max(maxLineWidth, text.node().getComputedTextLength()) }) let hoverHeight = text.length*20 + 15 rect .attr('class', 'mouseover-rect') .attr('width', maxLineWidth + 20) .attr('height', hoverHeight) .attr('x', -(maxLineWidth + 20)/2) .attr('y', 0) rectTitle .attr('class', 'mouseover-rect-title') .attr('width', maxLineWidth + 20) .attr('height', spacing[0] + 5) .attr('x', -(maxLineWidth + 20)/2) .attr('y', 0) const pad = 10; let halfRect = (maxLineWidth + 20)/2; if (x - halfRect - pad < 0) { x -= x - halfRect - pad } else if (x + halfRect + pad > w) { x += w - (x + halfRect + pad) } let mouseY = y - hoverHeight - pad; if (y - hoverHeight - pad*2 < 0) { mouseY += hoverHeight + pad*2; } mouseoverLayer.attr('transform', `translate(${x}, ${mouseY})`) }