1

I'm building a resource map with SVGs. When a user clicks on an individual element, I would like to position a popover over the center of that element. However, since the map is rotated via CSS, techniques like this one have been unsuccessful.

Here's my javascript:

Map.popup = function(e) {
    var rect = $(this);
    var offset = $(this).offset();

    var rectWidth = $(this).attr('width').replace(/[^-\d\.]/g, '');
    var rectHeight = $(this).attr('height').replace(/[^-\d\.]/g, '');

    var centerX = offset.left - rectWidth/2;
    var centerY = offset.top - rectHeight/2;

    $('.popup').css({
       'top' : centerY,
       'left' : centerX,
    });
}

Here's the markup:

    <div id="map">
    <svg width="1088px" height="1088px" xmlns="http://www.w3.org/2000/svg">
        <g transform="translate(288.0 32.0) rotate(45 256.0 512.0)">
            <rect id="0" x="8px" y="8px" width="51px" height="230px"></rect>
            <rect id="1" x="67px" y="8px" width="112px" height="38px"></rect>
            <rect id="2" x="187px" y="8px" width="144px" height="38px"></rect>
            <rect id="3" x="339px" y="8px" width="165px" height="38px"></rect>
            <rect id="4" x="67px" y="54px" width="112px" height="44px"></rect>
            <rect id="5" x="187px" y="54px" width="144px" height="75px"></rect>
            <rect id="6" x="339px" y="54px" width="35px" height="24px"></rect>
            <rect id="7" x="382px" y="54px" width="122px" height="51px"></rect>
            <rect id="8" x="339px" y="86px" width="35px" height="204px"></rect>
            <rect id="9" x="67px" y="106px" width="52px" height="132px"></rect>
            <rect id="10" x="127px" y="106px" width="52px" height="132px"></rect>
            <rect id="11" x="382px" y="113px" width="122px" height="78px" class=""></rect>
            <rect id="12" x="187px" y="137px" width="144px" height="70px"></rect>
            <rect id="13" x="382px" y="199px" width="122px" height="91px"></rect>
            <rect id="14" x="187px" y="215px" width="144px" height="65px"></rect>
            <rect id="15" x="8px" y="246px" width="171px" height="58px" class="selected"></rect>
            <rect id="16" x="187px" y="288px" width="144px" height="70px"></rect>
            <rect id="17" x="339px" y="298px" width="165px" height="60px" class=""></rect>
            <rect id="18" x="8px" y="312px" width="171px" height="50px"></rect>
            <rect id="19" x="187px" y="366px" width="144px" height="74px"></rect>
            <rect id="20" x="339px" y="366px" width="165px" height="28px"></rect>
            <rect id="21" x="8px" y="370px" width="171px" height="58px"></rect>
            <rect id="22" x="339px" y="402px" width="165px" height="38px"></rect>
            <rect id="23" x="8px" y="436px" width="171px" height="70px"></rect>
            <rect id="24" x="187px" y="448px" width="87px" height="58px"></rect>
            <rect id="25" x="282px" y="448px" width="49px" height="58px"></rect>
            <rect id="26" x="339px" y="448px" width="165px" height="58px"></rect>
            <rect id="27" x="8px" y="514px" width="171px" height="67px"></rect>
            <rect id="28" x="187px" y="514px" width="87px" height="67px"></rect>
            <rect id="29" x="282px" y="514px" width="49px" height="67px"></rect>
            <rect id="30" x="339px" y="514px" width="19px" height="44px"></rect>
            <rect id="31" x="366px" y="514px" width="46px" height="44px"></rect>
            <rect id="32" x="420px" y="514px" width="84px" height="22px"></rect>
            <rect id="33" x="420px" y="544px" width="84px" height="69px"></rect>
            <rect id="34" x="339px" y="566px" width="73px" height="53px"></rect>
            <rect id="35" x="8px" y="589px" width="171px" height="55px"></rect>
            <rect id="36" x="187px" y="589px" width="24px" height="36px"></rect>
            <rect id="37" x="219px" y="589px" width="112px" height="36px"></rect>
            <rect id="38" x="420px" y="621px" width="84px" height="71px"></rect>
            <rect id="39" x="339px" y="627px" width="73px" height="99px"></rect>
            <rect id="40" x="187px" y="633px" width="24px" height="105px"></rect>
            <rect id="41" x="219px" y="633px" width="112px" height="105px"></rect>
            <rect id="42" x="8px" y="652px" width="103px" height="36px"></rect>
            <rect id="43" x="119px" y="652px" width="60px" height="179px"></rect>
            <rect id="44" x="8px" y="696px" width="103px" height="49px"></rect>
            <rect id="45" x="420px" y="700px" width="84px" height="26px"></rect>
            <rect id="46" x="339px" y="734px" width="165px" height="46px"></rect>
            <rect id="47" x="187px" y="746px" width="24px" height="85px"></rect>
            <rect id="48" x="219px" y="746px" width="112px" height="34px"></rect>
            <rect id="49" x="8px" y="753px" width="103px" height="122px"></rect>
            <rect id="50" x="219px" y="788px" width="112px" height="43px"></rect>
            <rect id="51" x="339px" y="788px" width="165px" height="43px"></rect>
            <rect id="52" x="119px" y="839px" width="92px" height="177px"></rect>
            <rect id="53" x="219px" y="839px" width="46px" height="177px"></rect>
            <rect id="54" x="273px" y="839px" width="58px" height="53px"></rect>
            <rect id="55" x="339px" y="839px" width="58px" height="53px"></rect>
            <rect id="56" x="405px" y="839px" width="99px" height="53px"></rect>
            <rect id="57" x="8px" y="883px" width="103px" height="39px"></rect>
            <rect id="58" x="273px" y="900px" width="124px" height="116px"></rect>
            <rect id="59" x="405px" y="900px" width="19px" height="116px"></rect>
            <rect id="60" x="432px" y="900px" width="72px" height="116px"></rect>
            <rect id="61" x="8px" y="930px" width="103px" height="86px"></rect>
        </g>
    </svg>
</div>

You can see a version of the map (and its imperfect positioning) here: http://cityasacampus.org/map/.

Any ideas on how to better target the center of each ?

Community
  • 1
  • 1
Cameron Scott
  • 1,276
  • 2
  • 17
  • 37
  • Because u used the `transform="translate(288.0 32.0) rotate(45 256.0 512.0)`, your real `height` isn't the value as it is on your `height=XX`. So you'll need to calculate your real height and then here you go, you'll be able to set the center :) – dpedoneze Jul 31 '15 at 01:35

2 Answers2

2

First of all need to use getBoundingClientRect() to get the actual width of the bounding area of the clicked SVG Element since its now rotated. Then you need to add half of that to your offsets rather than minus, that will get your popup top left corner on the center of the SVG clicked element.

If you also take 250px(the width of the Popup Element) off the centerX calculation, the popup Arrow point (that's top right) should center in the middle of your clicked element nicely.

New code:

Map.popup = function(e) {
 var rect = $(this);
 var offset = $(this).offset();

 var rectWidth = $(this)[0].getBoundingClientRect().width;
 var rectHeight = $(this)[0].getBoundingClientRect().height;

 var centerX = offset.left + rectWidth/2 - 250;
 var centerY = offset.top + rectHeight/2;

 $('.popup').css({
   'top' : centerY,
   'left' : centerX,
 });
}
sjm
  • 5,378
  • 1
  • 26
  • 37
2

As @sjm pointed out, you can use getBoundingCliendRect() for getting your "real" height/width, but it won't work applying on $(this).

Map.popup = function(e) {    
  var rect          = $(this);
      offset        = $(this).offset(),
      canvas        = document.getElementById(rect.prop('id')),
      rectWidth     = canvas.getBoundingClientRect().width,
      rectHeight    = canvas.getBoundingClientRect().height,
      popoverWidth  = 250,
      popoverHeight = $('.popup').height(),
      centerX       = offset.left - popoverWidth + rectWidth/2,
      centerY       = offset.top + rectHeight/2;

  $('.popup').css({
     'top' : centerY,
     'left' : centerX,
  });
}

And also your centerX and centerY was wrong, I've corrected them.

Cheers!

dpedoneze
  • 949
  • 7
  • 17
  • Yes nice spotting, $(this)[0].getBoundingClientRect() would work instead, I've updated answer for completeness – sjm Jul 31 '15 at 02:50