Issue
I've built an SVG map where you can either hover over a separate list of names on the left which will trigger a tooltip. Or hover over the numbered icon on the map itself which also triggers the tooltip.
However I can't successfully get the tooltip to re-position itself relative to each numbered icon.
var iconPos = myicon.getBoundingClientRect();
mypopup.style.left = (iconPos.right + 20) + "px";
mypopup.style.top = (window.scrollY + iconPos.top - 60) + "px";
mypopup.style.display = "block";
I was previously trying to use the code above but it was making the tooltip position top: 6451px;
+.
I'd like the tooltip to appear central to the numbered icon (map__plot__item
) which has the class selected
.
Below is a demo I've created to show how it currently works with the tooltip positioned top right. JS Fiddle here too.
$( ".map__list__item" ).on( "mouseover", function() {
var tooltipCopy = $(this).html();
$(this).addClass('selected');
$(this).siblings('li').removeClass('selected');
$('#' + $(this).data('map')).addClass('selected');
$('#' + $(this).data('map')).siblings('g').removeClass('selected');
$("#mypopup").show().html(tooltipCopy);
});
$( ".map__list__item" ).on( "mouseout", function() {
$(this).removeClass('selected');
$(this).siblings('li').removeClass('selected');
$('#' + $(this).data('map')).removeClass('selected');
$('#' + $(this).data('map')).siblings('g').removeClass('selected');
$("#mypopup").hide().empty();
});
$('.map__plot__item').on( "mouseover", function() {
var tooltipCopy = $(this).data('list');
$(this).addClass('selected');
$(this).siblings('g').removeClass('selected');
$("#mypopup").show().html(tooltipCopy);
});
$('.map__plot__item').on( "mouseout", function() {
$(this).removeClass('selected');
$(this).siblings('g').removeClass('selected');
$("#mypopup").hide().empty();
});
body {
margin: 0;
padding: 0;
}
#top-section {
height: 250px;
background: red;
}
h1 {
color: white;
text-align: center;
font-size: 40px;
line-height: 40px;
font-family: Arial;
}
#map-wrapper {
position: relative;
width: 100%;
}
#mapNavigation {
width: 200px;
flex-shrink: 0
}
#mapNavigation li {
line-height: 25px;
}
.d-flex {
display: flex;
}
svg {
width: 100%;
}
#mypopup {
width: 200px;
height: 20px;
padding: 10px;
font-family: Arial, sans-serif;
font-size: 18px;
color: $dark;
background-color: white;
border-radius: 6px;
position: absolute;
display: none;
top: 0;
right: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="top-section">
<h1>
Heading here
</h1>
</div>
<div class="d-flex">
<div id="mapNavigation">
<ol>
<li id="restaurant-list-01" class="map__list__item" data-map="restaurant-01">
Name here 01
</li>
<li id="restaurant-list-02" class="map__list__item" data-map="restaurant-02">
Name here 02
</li>
<li id="restaurant-list-03" class="map__list__item" data-map="restaurant-03">
Name here 03
</li>
<li id="restaurant-list-04" class="map__list__item" data-map="restaurant-04">
Name here 04
</li>
<li id="restaurant-list-05" class="map__list__item" data-map="restaurant-05">
Name here 05
</li>
<li id="restaurant-list-06" class="map__list__item" data-map="restaurant-06">
Name here 06
</li>
<li id="restaurant-list-07" class="map__list__item" data-map="restaurant-07">
Name here 07
</li>
<li id="restaurant-list-08" class="map__list__item" data-map="restaurant-08">
Name here 08
</li>
</ol>
</div>
<div id="map-wrapper">
<svg width="100%" viewBox="0 0 1336 942" fill="none">
<g id="Layer_2">
<rect width="1336" height="942" fill="#D9D9D9"/>
</g>
<g id="Layer_1">
<g id="restaurant-05" data-list="Name here 05" class="map__plot__item">
<circle cx="554" cy="336" r="36" fill="#B93333"/>
<path d="M547.5,340.8l3.8-0.4c0.1,0.9,0.4,1.6,1,2.1c0.5,0.5,1.2,0.8,1.9,0.8c0.8,0,1.5-0.3,2-1
c0.6-0.7,0.8-1.6,0.8-3c0-1.2-0.3-2.2-0.8-2.8c-0.5-0.6-1.3-0.9-2.1-0.9c-1.1,0-2.1,0.5-3,1.5l-3.1-0.5l2-10.4H560v3.6h-7.2
l-0.6,3.4c0.9-0.4,1.7-0.6,2.6-0.6c1.7,0,3.1,0.6,4.3,1.9c1.2,1.2,1.8,2.8,1.8,4.8c0,1.6-0.5,3.1-1.4,4.4
c-1.3,1.8-3.1,2.7-5.4,2.7c-1.8,0-3.4-0.5-4.5-1.5C548.4,343.9,547.7,342.5,547.5,340.8z" fill="white" />
</g>
<g id="restaurant-03" data-list="Name here 03" class="map__plot__item">
<circle cx="732" cy="320" r="36" fill="#B93333"/>
<path d="M725.3,324.7l3.7-0.5c0.1,0.9,0.4,1.7,1,2.2c0.5,0.5,1.1,0.8,1.9,0.8c0.8,0,1.5-0.3,2-0.9
c0.5-0.6,0.8-1.4,0.8-2.4c0-1-0.3-1.7-0.8-2.3c-0.5-0.6-1.2-0.8-1.9-0.8c-0.5,0-1.1,0.1-1.8,0.3l0.4-3.1c1,0,1.8-0.2,2.4-0.7
c0.5-0.5,0.8-1.1,0.8-1.9c0-0.7-0.2-1.2-0.6-1.6s-0.9-0.6-1.6-0.6c-0.7,0-1.2,0.2-1.7,0.7c-0.5,0.5-0.7,1.1-0.8,2l-3.5-0.6
c0.2-1.2,0.6-2.2,1.1-2.9c0.5-0.7,1.2-1.3,2.1-1.7c0.9-0.4,1.9-0.6,3-0.6c1.9,0,3.4,0.6,4.5,1.8c0.9,1,1.4,2.1,1.4,3.3
c0,1.8-1,3.2-2.9,4.2c1.1,0.2,2.1,0.8,2.7,1.7c0.7,0.9,1,1.9,1,3.1c0,1.8-0.6,3.3-1.9,4.5c-1.3,1.2-2.9,1.9-4.8,1.9
c-1.8,0-3.3-0.5-4.5-1.6C726.1,327.7,725.5,326.4,725.3,324.7z" fill="white"/>
</g>
<g id="restaurant-02" data-list="Name here 02" class="map__plot__item">
<circle cx="988" cy="240" r="36" fill="#B93333"/>
<path d="M994.4,246.4v3.6h-13.5c0.1-1.3,0.6-2.6,1.3-3.8c0.7-1.2,2.2-2.8,4.3-4.8c1.7-1.6,2.8-2.7,3.2-3.3
c0.5-0.8,0.8-1.6,0.8-2.4c0-0.9-0.2-1.5-0.7-2c-0.5-0.5-1.1-0.7-1.9-0.7c-0.8,0-1.4,0.2-1.9,0.7s-0.7,1.3-0.8,2.4l-3.8-0.4
c0.2-2.1,0.9-3.6,2.1-4.6c1.2-0.9,2.7-1.4,4.5-1.4c2,0,3.5,0.5,4.7,1.6c1.1,1.1,1.7,2.4,1.7,4c0,0.9-0.2,1.8-0.5,2.6
c-0.3,0.8-0.8,1.7-1.5,2.6c-0.5,0.6-1.3,1.4-2.5,2.6c-1.2,1.1-2,1.9-2.3,2.2c-0.3,0.4-0.6,0.7-0.8,1.1H994.4z" fill="white"/>
</g>
<g id="restaurant-04" data-list="Name here 04" class="map__plot__item">
<circle cx="1094" cy="494" r="36" fill="#B93333"/>
<path d="M1094.9,504v-4h-8.2v-3.4l8.7-12.7h3.2v12.7h2.5v3.4h-2.5v4H1094.9z M1094.9,496.6v-6.9l-4.6,6.9H1094.9z" fill="white"/>
</g>
<g id="restaurant-01" data-list="Name here 01" class="map__plot__item">
<circle cx="916" cy="664" r="36" fill="#B93333"/>
<path d="M919.2,674h-3.8v-14.5c-1.4,1.3-3.1,2.3-5,2.9v-3.5c1-0.3,2.1-0.9,3.3-1.9c1.2-0.9,2-2,2.4-3.2h3.1V674z" fill="white"/>
</g>
<g id="restaurant-06" data-list="Name here 06" class="map__plot__item">
<circle cx="416" cy="748" r="36" fill="#B93333"/>
<path d="M422.4,742.9l-3.7,0.4c-0.1-0.8-0.3-1.3-0.7-1.7c-0.4-0.4-0.9-0.5-1.5-0.5c-0.8,0-1.5,0.4-2.1,1.1
c-0.6,0.7-0.9,2.2-1.1,4.6c1-1.1,2.1-1.7,3.6-1.7c1.6,0,3,0.6,4.1,1.8c1.1,1.2,1.7,2.8,1.7,4.7c0,2.1-0.6,3.7-1.8,4.9
c-1.2,1.2-2.7,1.9-4.6,1.9c-2,0-3.7-0.8-5-2.4c-1.3-1.6-2-4.2-2-7.7c0-3.7,0.7-6.3,2-7.9c1.4-1.6,3.1-2.4,5.3-2.4
c1.5,0,2.8,0.4,3.8,1.3C421.5,740,422.1,741.2,422.4,742.9z M413.7,751.2c0,1.2,0.3,2.2,0.9,2.9c0.6,0.7,1.2,1,2,1
c0.7,0,1.3-0.3,1.8-0.8c0.5-0.6,0.7-1.5,0.7-2.7c0-1.3-0.3-2.3-0.8-2.9c-0.5-0.6-1.1-0.9-1.9-0.9c-0.7,0-1.4,0.3-1.9,0.9
C414,749.3,413.7,750.1,413.7,751.2z" fill="white"/>
</g>
<g id="restaurant-07" data-list="Name here 07" class="map__plot__item">
<circle cx="260" cy="220" r="36" fill="#B93333"/>
<path d="M253.4,213.8v-3.6h13.1v2.8c-1.1,1.1-2.2,2.6-3.3,4.6c-1.1,2-2,4.1-2.6,6.4c-0.6,2.2-0.9,4.2-0.9,6h-3.7
c0.1-2.8,0.6-5.6,1.7-8.5c1.1-2.9,2.5-5.5,4.3-7.7H253.4z" fill="white"/>
</g>
<g id="restaurant-08" data-list="Name here 08" class="map__plot__item">
<circle cx="490" cy="548" r="36" fill="#B93333"/>
<path d="M486.7,547.2c-1-0.4-1.7-1-2.2-1.7c-0.4-0.7-0.7-1.5-0.7-2.4c0-1.5,0.5-2.7,1.6-3.7c1-1,2.5-1.5,4.5-1.5
c1.9,0,3.4,0.5,4.4,1.5c1.1,1,1.6,2.2,1.6,3.7c0,0.9-0.2,1.8-0.7,2.5c-0.5,0.7-1.2,1.3-2,1.7c1.1,0.4,2,1.1,2.5,2
c0.6,0.9,0.9,1.8,0.9,3c0,1.9-0.6,3.4-1.8,4.5c-1.2,1.2-2.7,1.7-4.7,1.7c-1.8,0-3.3-0.5-4.6-1.4c-1.4-1.1-2.1-2.7-2.1-4.6
c0-1.1,0.3-2.1,0.8-3C484.7,548.4,485.5,547.7,486.7,547.2z M487.5,543.3c0,0.8,0.2,1.4,0.6,1.8c0.4,0.4,1,0.6,1.7,0.6
c0.7,0,1.3-0.2,1.8-0.6c0.4-0.4,0.7-1,0.7-1.8c0-0.7-0.2-1.3-0.7-1.7c-0.4-0.4-1-0.7-1.7-0.7c-0.7,0-1.3,0.2-1.8,0.7
C487.7,542,487.5,542.6,487.5,543.3z M487.1,551.9c0,1.1,0.3,1.9,0.8,2.5c0.5,0.6,1.2,0.9,2,0.9c0.8,0,1.4-0.3,2-0.8
c0.5-0.6,0.8-1.4,0.8-2.5c0-0.9-0.3-1.7-0.8-2.3c-0.5-0.6-1.2-0.9-2-0.9c-0.9,0-1.6,0.3-2.1,1
C487.4,550.4,487.1,551.1,487.1,551.9z" fill="white"/>
</g>
</g>
</svg>
<div id="mypopup"></div>
</div>
</div>
Solution
- Simplify your HTML attributes to only use
data-map
(instead of classes, IDs, etc) - Calculate the percentage on where to place the popup getting the SVG's viewBox's width/height and the targeting
<g>
getBBoxx
andy
positions
const $popup = $("#mypopup");
const $liAll = $("#mapNavigation li[data-map]");
const $svg = $("#map-wrapper svg");
const $gAll = $("g[data-map]", $svg);
$("[data-map]").on("mouseenter mouseleave", function(ev) {
const id = $(this).data("map");
const $li = $(`#mapNavigation li[data-map="${id}"]`);
const $g = $(`g[data-map="${id}"]`, $svg);
const desc = $li.text();
$liAll.add($gAll).removeClass("selected");
if (ev.type === "mouseenter") {
$li.add($g).addClass("selected");
const {width, height} = $svg.prop("viewBox").baseVal;
const {x, y} = $g[0].getBBox();
$popup
.show()
.text(desc)
.css({
left: `${x / width * 100}%`,
top: `${y / height * 100}%`
});
} else {
$li.add($g).removeClass("selected");
$popup.hide().text("");
}
});
body {
margin: 0;
padding: 0;
font: 1rem/1.4 Arial, sans-serif;
}
#top-section {
height: 250px;
background: red;
}
h1 {
color: white;
text-align: center;
font-size: 40px;
line-height: 40px;
font-family: Arial;
}
#map-wrapper {
position: relative;
width: 100%;
background: green;
align-self: start; /* NEEDED */
}
#mapNavigation {
flex: 1 0 auto;
li {
&.selected {
color: red;
}
}
}
svg {
display: block;
width: 100%;
g.selected {
circle{
fill: #fff;
}
text {
fill: #000;
}
}
text {
font: 2.2em/1 sans-serif;
text-anchor: middle;
fill: #fff;
}
}
#mypopup {
position: absolute;
display: none;
width: 200px;
height: 20px;
padding: 10px;
background-color: white;
border-radius: 6px;
translate: -50% -100%;
top: 0;
right: 0;
}
.d-flex {
display: flex;
}
<div id="top-section">
<h1>Heading here</h1>
</div>
<div class="d-flex">
<div id="mapNavigation">
<ol>
<li data-map="restaurant-01">Name here 01</li>
<li data-map="restaurant-02">Name here 02</li>
<li data-map="restaurant-03">Name here 03</li>
<li data-map="restaurant-04">Name here 04</li>
<li data-map="restaurant-05">Name here 05</li>
<li data-map="restaurant-06">Name here 06</li>
<li data-map="restaurant-07">Name here 07</li>
<li data-map="restaurant-08">Name here 08</li>
</ol>
</div>
<div id="map-wrapper">
<svg viewBox="0 0 1336 942" fill="none">
<g id="Layer_2">
<rect width="1336" height="942" fill="#D9D9D9"/>
</g>
<g id="Layer_1">
<g data-map="restaurant-05">
<circle cx="554" cy="336" r="36" fill="#B93333"/>
<text x="554" y="336" dy="0.4em">5</text>
</g>
<g data-map="restaurant-03">
<circle cx="732" cy="320" r="36" fill="#B93333"/>
<text x="732" y="320" dy="0.4em">3</text>
</g>
<g data-map="restaurant-02">
<circle cx="988" cy="240" r="36" fill="#B93333"/>
<text x="988" y="240" dy="0.4em">2</text>
</g>
<g data-map="restaurant-04">
<circle cx="1094" cy="494" r="36" fill="#B93333"/>
<text x="1094" y="494" dy="0.4em">4</text>
</g>
<g data-map="restaurant-01">
<circle cx="916" cy="664" r="36" fill="#B93333"/>
<text x="916" y="664" dy="0.4em">1</text>
</g>
<g data-map="restaurant-06">
<circle cx="416" cy="748" r="36" fill="#B93333"/>
<text x="416" y="748" dy="0.4em">6</text>
</g>
<g data-map="restaurant-07">
<circle cx="260" cy="220" r="36" fill="#B93333"/>
<text x="260" y="220" dy="0.4em">7</text>
</g>
<g data-map="restaurant-08">
<circle cx="490" cy="548" r="36" fill="#B93333"/>
<text x="490" y="548" dy="0.4em">8</text>
</g>
</g>
</svg>
<div id="mypopup"></div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
Answered By - Roko C. Buljan
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.