javascript - Place one SVG element on top of another when using a non proportional viewbox -


i have svg:

<svg id="root" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="347.27mm" viewbox="0 0 409.32783 1230.3321" width="115.48mm" version="1.1">   <circle id="b1" cx="0" cy="0" r="15" class="bottom" />   <circle id="b2" cx="120" cy="100" r="15" class="bottom" />   <g transform="translate(17,43)">     <circle id="b3" cx="240" cy="200" r="15" class="bottom" />     <circle id="b4" cx="360" cy="300" r="15" class="bottom" />   </g>    <!--      <g transform="translate(10,20)"> -->   <circle id="t1" cx="80" cy="30" r="15" class="top" />   <circle id="t2" cx="130" cy="30" r="15" class="top" />   <!--        <g transform="translate(10,20)"> -->   <circle id="t3" cx="180" cy="30" r="15" class="top" />   <circle id="t4" cx="230" cy="30" r="15" class="top" />   <!--    </g> -->   <!--      </g> --> </svg> 

after red balls coordinates changed code follows. renders as:

rendered svg

i want center red balls on top of green ones. have solution works if remove viewbox attribute in svg tag. unfortunately can't that. however, works if viewbox isn't there:

var svg = document.getelementbyid("root");  (var index = 1; index <= 4; index++) {   var bottom = svg.getelementbyid("b" + index);   var top = svg.getelementbyid("t" + index);    var targetx = parsefloat(top.getattribute("cx"));   var targety = parsefloat(top.getattribute("cy"));    var center = getelementcenter(svg, bottom);    top.setattribute("cx", parsefloat(center.x));   top.setattribute("cy", parsefloat(center.y)); }  function gettransformedcoords(x, y, matrix) {   var transformedx = x * matrix.a + y * matrix.c + matrix.e;   var transformedy = x * matrix.b + y * matrix.d + matrix.f;    return {     x: transformedx,     y: transformedy   }; }  function getelementcenter(svg, element) {   var x, y, width = 0, height = 0;    var boundingbox = element.getbbox();   var centerx = boundingbox.x + (boundingbox.width / 2);   var centery = boundingbox.y + (boundingbox.height / 2);    var out = gettransformedcoords(centerx, centery, element.getctm()); // getctm affected viewport    centerx = out.x;   centery = out.y;    return {     x: centerx,     y: centery   }; } 

my working theory because viewbox hasn't got same ratio viewport. don't know how fix that.

i want use plain javascript this. if nice use suitable library.

questions:

  1. how can make work while keeping viewbox?
  2. is possible make account transformations in green circles well? commented out in svg, nice have solid works when they're in there well. number 1 enough me accept answer.

jsfiddle if want try code out: https://jsfiddle.net/kentl/gpqcdecx/

ps. here's css if want style it:

.top {fill:red;animation:fall 4s ease-in-out infinite;} .bottom{fill:green;} @keyframes fall {0%{opacity:0.0;}50%{opacity:1.0;}100%{opacity:0.0;}} 

just use gettransformtoelement. chrome you'll need polyfill though it's no longer natively implemented there.

// goal place red circles on top of green ones    // working theory:  //   viewbox hasn't got same ratio viewport, affects returned transformation, returning  //   matrix larger numbers 1 scaling x , y. matrix used convert  //   local coordinate space in bottom element, global 1 used top element, coordinates  //   scaled slightly.. when coordinates set in top element, they'll affected again  //   same up-scaling. making them become more , more off further 0,0 come.    // question:  // 1. how can fixed?  // 2. if it's not hard: uncomment <g>'s in svg. how compensate affected top ctm well?      console.clear();    var svg = document.getelementbyid("root");    (var index = 1; index <= 4; index++) {    var bottom = document.getelementbyid("b" + index);    var top1 = document.getelementbyid("t" + index);      var targetx = parsefloat(top1.getattribute("cx"));    var targety = parsefloat(top1.getattribute("cy"));      var center = getelementcenter(svg, bottom);        t = bottom.gettransformtoelement(top1);      top1.setattribute("cx", parsefloat(center.x) + t.e);    top1.setattribute("cy", parsefloat(center.y) + t.f);  }    function getelementcenter(svg, element) {    var x, y, width = 0, height = 0;      var boundingbox = element.getbbox();    var centerx = boundingbox.x + (boundingbox.width / 2);    var centery = boundingbox.y + (boundingbox.height / 2);      return {      x: centerx,      y: centery    };  }
.top {    fill: red;    animation: fall 4s ease-in-out infinite;  }    .bottom {    fill: green;  }    @keyframes fall {    0% {      opacity: 0.0;    }    50% {      opacity: 1.0;    }    100% {      opacity: 0.0;    }  }
<svg id="root" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="347.27mm" viewbox="0 0 409.32783 1230.3321" width="115.48mm" version="1.1">    <circle id="b1" cx="0" cy="0" r="15" class="bottom" />    <circle id="b2" cx="120" cy="100" r="15" class="bottom" />    <g transform="translate(17,43)">      <circle id="b3" cx="240" cy="200" r="15" class="bottom" />      <circle id="b4" cx="360" cy="300" r="15" class="bottom" />    </g>      <!--      <g transform="translate(10,20)"> -->    <circle id="t1" cx="80" cy="30" r="15" class="top" />    <circle id="t2" cx="130" cy="30" r="15" class="top" />    <!--        <g transform="translate(10,20)"> -->    <circle id="t3" cx="180" cy="30" r="15" class="top" />    <circle id="t4" cx="230" cy="30" r="15" class="top" />    <!--    </g> -->    <!--      </g> -->  </svg>


Comments

Popular posts from this blog

authentication - Mongodb revoke acccess to connect test database -

r - Update two sets of radiobuttons reactively - shiny -

ios - Realm over CoreData should I use NSFetchedResultController or a Dictionary? -