Firefox svg rendering: how to get real g position? - javascript

I have a page with a svg loaded via object.
Then, I call a function that loads a div, using width, height, left and top of an internal g element
var cartina = document.getElementById(whatMap);
var cartinaContext;
cartina.addEventListener("load",function(){
cartinaContext = cartina.contentDocument;
var el = $("#mappaBase", cartinaContext)[0];
var rect = el.getBoundingClientRect();
var whatContainer = "#containerIcone"+whatMap;
$(whatContainer).css("position", "absolute");
$(whatContainer).width(rect.width);
$(whatContainer).height(rect.height);
$(whatContainer).css("left", rect.left);
$(whatContainer).css("top", rect.top);
}
I'm using getBoundingClientRect(). I'm applying the div #containerIcone over the svg.
In Chrome it works smoothly well. The problem is in Firefox: when I load the page, width and height are properly loaded but left and top are not. If I inspect the svg with Firefox, it appears that the g element is placed in a fixed position, while the rendered g element has another one (responsive to window dimensions and other elements position). Still, the g fixed element reacts well to window various sizes. The div is placed over the g element fixed inspect-position.
Inspecting the same element with Chrome reveals that the g element inspect box is drawed everytime where the g rendered element is.
How can I make this work in Firefox?

I found a solution, it's working cross-browser.
Instead of positioning with .top and .left of the nested g element, I get width and height of nested element
var el = $(nestedElement);
var rect = el.getBoundingClientRect();
Then I get width and height of the parent svg element
var rectSvg = mysvg.getBoundingClientRect();
Then I subtract the el width and height from the svg ones, and divide results by 2. The final result is the white space the svg has inside it, top and left, used to center the rendered element el inside the svg element (used by browser to mantain aspect ratio). Then I apply those results as css top and left of my div containing icons - it will be positioned exactly over the g el element.
var leftSpace = (rectSvg.width - rect.width)/2;
var topSpace = (rectSvg.height - rect.height)/2;
$(myPositionedDiv).css("left", leftSpace);
$(myPositionedDiv).css("top", topSpace);
This manner, however Firefox positions the element despite of rendering, left and top are correctly calculated.

Related

How to get screen coordinates with getBoundingClientRect() in the presence of CSS zoom?

I'm trying to find the bounding box of an HTML element using Javascript in screen coordinates so that I can use external tools (such as ffmpeg's x11grab screen recording functionality) to take screenshots/videos of that element by itself.
If there is no CSS zoom present, then I can find the bounding box for element elem like this:
let viewportTop = window.screenY + (window.outerHeight - window.innerHeight);
let viewportLeft = window.screenX;
let rect = elem.getBoundingClientRect();
let width = rect.width;
let height = rect.height;
let left = viewportLeft + rect.left;
let top = viewportTop + rect.top;
I can then use these width, height, left, top coordinates to record the desired box on the browser window.
However, sometimes I want to increase the zoom of the element to make things easier to see:
elem.style.zoom = "2";
Having done this, the bounding box returned by elem.getBoundingClientRect() is now scaled down by a factor of 2. If I use the approach above to calculate my recording bounding box, it no longer lines up with the element.
I've had some success with calling window.getComputedStyle(elem, null).getPropertyValue("zoom"), parsing the zoom number, and using it to correct the bounding box. However, this isn't a perfect solution--what if I want to zoom document.body by some amount and also zoom the target element by some amount?
So, I'm wondering if there's a universal way to convert the coordinates from elem.getBoundingClientRect to screen coords that works even when CSS zoom is applied to various elements.
I considered using the browser's own zoom rather than CSS zoom, but I would rather not since I'm using Selenium to set this stuff up and I've seen dire warnings about adjusting the browser zoom with Selenium here.

Detect element position on a screen using javascript

Is there a way using javascript to detect the absolute position of where you are positioned on a monitor? For example Intersection Observer can tell you if your element is within the viewport of the browser, but it cannot tell you if the browser is halfway off the users monitor, and your element is outside of an actual persons view.
You can find the position of the element using getBoundingClientRect
var x = document.getElementById("elementId").getBoundingClientRect().x;
var y = document.getElementById("elementId").getBoundingClientRect().y;
//Your element position
var position = [x, y];
If your element is off the viewport, it would have negative values depending on its position from top-left.

How to get mouse coordinates inside a scrollable div or svg from the top left corner?

I have a scrollable svg element (it's width and height are constant but it is actually larger in dimension, and hence gets scrollbars because I have set overflow: scroll;).
This svg element is inside the body with other content. The body can also be scrolled around.
Without using JQuery, how do I get the mouse coordinates from the top left corner of the svg? By top left, I mean the top left including regions of the svg that have been scrolled out. (If I scroll to the very right in my svg I should get a high x value because the point is horizontally far from the actual left of the svg regardless of how it is scrolled).
Here is my attempt:
return new Vector(event.pageX - svg.offsetLeft + svg.scrollLeft,
event.pageY - svg.offsetTop + svg.scrollTop);
It doesn't work. scrollLeft and scrollTop are always 0.
Try leaving the SVG at its natural width and height and place it inside a <div> that has { overflow: scroll } and do the same computation on the DIV.
That should work in case there are browser quirks with reading the scrollLeft/scrollTop properties on SVG elements (I haven't tested yet to see if that's the case).
Update: you can use getBoundingClientRect() like this
var rect = container.getBoundingClientRect();
var x = e.clientX + container.scrollLeft - rect.left;
var y = e.clientY + container.scrollTop - rect.top;
Live example: http://jsfiddle.net/aag5fd39/1/

How to make a svg element (e.g. rectangle) scrollIntoView?

I have a svg in graph panel. All nodes in the svg are listed in another panel. I hope that by clicking the node in node list, svg can scroll to that node. Each node is a rectangle. But I found that only the upper border is in view, while the rest part of the node are still out of the view. Is there any way to fix this problem? (either Javascript or Extjs)
This is my code:
function selectRectangle(Id){
var ele = Ext.get(Id);
ele.scrollIntoView(Ext.get('graph-panel-body'), true);}
By whatever reason scrollIntoView seems not to work for SVG elements. This is what I do
suppose the svg is in a
<div id="container">
<svg ...>
...
<path id> ...</path>
</svg>
</div>
then suppose in the variable 'element' you have the element you want to scrollIntoView
var bbox = ele.getBBox()
var top = bbox.y + bbox.y2
top = 50 * Math.floor(top/50)
$("#container").get(0).scrollTop=top
I am not sure, but I observe that getBBox is pretty slow. So take care.
The problem is that the SVG element you are trying to scroll the view to probably has a y or dy attribute which offsets it from the top, and the scrollIntoView method in Chrome doesn't take that into account (in Firefox it does), therefor it will scroll to the top, because it thinks the element is there, because this is how SVG elements positioning works.. elements are all rendered from the very top left and then kind of "transformed" to their positions via x, y, dx, dy attributes.
There is an open bug which you can (and should) star:
https://bugs.chromium.org/p/chromium/issues/detail?id=803440

Position a div relavtive to another div: SVG issues

I have a div with an id="div_Diagram" that contains two other divs, div_CanvasHeader and div_Canvas, as shown. div_Canvas also contans an SVG, which in turn contains several rects. Each rect has is constructed in a way that its has a javascript script attached to its mouseover event with the x & y position values passed into the script.
Do to the nature of svgs, I'm not able to correctly position the tooltip division relative to the rect. I'd like to be able to use the rect coordinates (x&y) to position the tooltip relative to div_CanvasHeader or div_Diagram. Other then x & y, all other dimensions are fixed.
Here is the javascript. (Note that the tooltip is a telerik control. The Show() method does show the tooltip with all of the correct content but at the bottom left of page).
function showSVGTtip(elt, x, y) {
if (elt.hasAttribute("name")) {
var ttipText = elt.getAttribute("ttipText ");
var ttip = $find("<%=myToolTipDiv.ClientID %>");
document.getElementById("ttipLabel").innerHTML = ttipText ;
ttip.show();
// Need to set position of ttip relative to other element such as pnlCanvasHeader
}
}
How do I position the tooltip div relative to one of the other divs? For example, if I have the id of the tooltip div, can I move it on the client relative to div_CanvasHeader? Does the tooltip need to be contained within the other div?

Categories