Ответ 1
Если ваша подсказка является элементом HTML, то вы хотите поместить ее относительно страницы в целом, а не внутренние координаты SVG, поэтому доступ к значению cx/cy просто усложняет ситуацию. Я не могу сказать точно, не глядя на ваш код, но если у вас есть какие-либо преобразования в ваших <svg>
или <g>
элементах, то это может быть то, что отбрасывает вас.
Однако существует гораздо более простое решение. Просто получите доступ к свойствам события по умолчанию .pageX
и .pageY
, которые дают положение мыши относительно тела HTML, и используйте эти координаты, чтобы поместить свою подсказку div.
Пример здесь: http://fiddle.jshell.net/tPv46/1/
Key code:
.on("mousemove", function () {
//console.log(d3.event);
return tooltip
.style("top", (d3.event.pageY + 16) + "px")
.style("left", (d3.event.pageX + 16) + "px");
})
Даже с вращательными преобразованиями в кругах SVG мышь знает, где она находится на странице, и всплывающая подсказка расположена соответственно.
Есть и другие способы сделать это, в том числе получить всплывающую подсказку для отображения в фиксированном местоположении относительно круга вместо того, чтобы следовать за мышью, но я просто проверил примеры, над которыми я работал, и понял, что они не пересекаются -browser, поэтому мне придется стандартизировать их и вернуться к вам. Тем временем я надеюсь, что это вернет вас к вашему проекту.
Изменить 1
Для сравнения, вот тот же пример, реализованный как с помощью HTML-подсказки (элемент <div>
), так и всплывающей подсказки SVG (элемент <g>
).
http://fiddle.jshell.net/tPv46/4/
Координаты событий мыши по умолчанию могут быть отличными для размещения элементов HTML, которые являются прямыми дочерними элементами <body>
, но они менее полезны для позиционирования элементов SVG. Функция d3.mouse()
вычисляет координаты мыши текущего события относительно заданной системы координат элемента SVG после того, как все преобразования были применены. Поэтому его можно использовать для получения координат мыши в форме, необходимой для установки всплывающей подсказки SVG.
Key code:
.on("mousemove", function () {
var mouseCoords = d3.mouse(
SVGtooltip[0][0].parentNode);
//the d3.mouse() function calculates the mouse
//position relative to an SVG Element, in that
//element coordinate system
//(after transform or viewBox attributes).
//Because we're using the coordinates to position
//the SVG tooltip, we want the coordinates to be
//with respect to that element parent.
//SVGtooltip[0][0] accesses the (first and only)
//selected element from the saved d3 selection object.
SVGtooltip
.attr("transform", "translate(" + (mouseCoords[0]-30)
+ "," + (mouseCoords[1]-30) + ")");
HTMLtooltip
.style("top", (d3.event.pageY + 16) + "px")
.style("left", (d3.event.pageX + 16) + "px");
})
Обратите внимание, что он работает, хотя я масштабировал SVG с помощью атрибута viewBox
и помещал всплывающую подсказку внутри <g>
с атрибутом преобразования.
Протестировано и работает в Chrome, Firefox и Opera (достаточно последние версии) - хотя текст в всплывающей подсказке SVG может проходить за его прямоугольник в зависимости от ваших настроек шрифта. Одна из причин использования HTML-подсказки! Другая причина заключается в том, что он не обрезается краем SVG.
Оставьте комментарий, если у вас есть ошибки в Safari или IE9/10/11. (IE8 и ниже не повезло, поскольку они не выполняют SVG).
Изменить 2
Итак, как насчет вашей оригинальной идеи, поместить всплывающую подсказку на самом круге? Есть определенные преимущества, позволяющие точно настроить кончик: лучше управлять макетом, и текст не шевелится с помощью мыши. И самое главное, вы можете просто поместить его один раз на событие mouseover вместо того, чтобы реагировать на каждое событие mousemove.
Но для этого вы больше не можете просто использовать положение мыши, чтобы выяснить, куда поместить всплывающую подсказку - вам нужно выяснить положение элемента, что означает, что вам приходится иметь дело с преобразованиями. Спецификация SVG представляет набор интерфейсов для размещения элементов SVG относительно других частей DOM.
Для преобразования двух систем преобразования SVG вы используете SVGElement.getTransformToElement(SVGElement)
; для преобразования между системой координат SVG и экраном вы используете SVGElement.getScreenCTM()
. Результатом являются матрицы преобразования, из которых вы можете
извлечь чистый горизонтальный и вертикальный перевод.
key code для всплывающей подсказки SVG
var tooltipParent = SVGtooltip[0][0].parentNode;
var matrix =
this.getTransformToElement(tooltipParent)
.translate(+this.getAttribute("cx"),
+this.getAttribute("cy"));
SVGtooltip
.attr("transform", "translate(" + (matrix.e)
+ "," + (matrix.f - 30) + ")");
key code для всплывающей подсказки HTML
var matrix = this.getScreenCTM()
.translate(+this.getAttribute("cx"),
+this.getAttribute("cy"));
absoluteHTMLtooltip
.style("left",
(window.pageXOffset + matrix.e) + "px")
.style("top",
(window.pageYOffset + matrix.f + 30) + "px");
Пример в реальном времени: http://fiddle.jshell.net/tPv46/89/
Снова, я был бы признателен за подтверждение от любого, кто может проверить это в Safari или IE, или в любом мобильном браузере. Я уверен, что я использовал стандартный API для всего, но только потому, что API является стандартным, это не значит, что он универсально реализован!