I need to get a boundingClientRect of an SVGElement which has been clipped - using this information, i want to position HTML elements on top of the SVG element.
My SVG looks like this (simplified, the original one has both multiple cascading viewports and multiple cascading transforms):
<svg width="96" height="80">
<clippath id="clip">
<path d="M 0 0 L 96 0 L 96 80 L 0 80 Z"/>
</clippath>
<g clip-path="url(#clip)">
<image x="0" y="-8" width="96" height="96" xlink:href="…" transform="…"/>
</g>
</svg>
I want to position HTML elements on top of the SVGGElement. To do this, i get the boundingClientRect of
the HTMLElement being positioned
the HTMLElements parent
Element ? that allows me to get the boundingClientRect of the SVGGelement with Clipping applied
In Chrome, this works by getting the boundingClientRect of the SVGPathElement. In Opera and Firefox, the resulting clientRect has width and height 0 (probably because the path element isn't displayed). The boundingClientRect of the SVGGelement itself gets its dimensions from contained SVGImageElement regardless of the clip-path applied.
I tried referencing the SVGPathElement through a SVGUseElement and getting the boundingClientRect of that - which seemed to work.
Is it really necessary to introduce another DOM element that is set to visibility hidden and pointer-events: none or does anyone know a better solution?
Related
I've a lot of SVG files (several graphics like, dogs, trees, birds, buildings etc.), and they are from different sources from web. I need to define height and width of these SVGs.
Example File:
<svg id="svg1" viewBox="0 0 36 33" xmlns="http://www.w3.org/2000/svg">
<path d="m18 0.0938-17.719 16.281h5.5625v15.531h24.312v-15.531h5.5625l-17.719-16.281z"/>
</svg>
I get the width and height of this:
var svg1 = document.getElementById('svg1');
console.log('client', svg1.clientWidth + 'x' + svg1.clientHeight);
And then modified the file with the results:
<svg width="630" height="577" viewBox="0 0 36 33" xmlns="http://www.w3.org/2000/svg">
<path d="m18 0.0938-17.719 16.281h5.5625v15.531h24.312v-15.531h5.5625l-17.719-16.281z"/>
</svg>
I am experienced in javascript and c#, but I don't know a way to achieve this.
P.S: The reason I need this: My wordpress custom product designer plugin uses SVG files to design custom products, but those SVG files must have width and height for my plugin to work properly.
if you are using SVG from material-ui, wrap it inside an IconButton (and define the height and width here). The svg takes the dimensions of the parent.
I'm trying to render a react component with an inline SVG element that has a text along a path. This is what is returned from the render method:
<div className="textsvg">
<svg width="100%" height="100%" viewBox="-50 -50 100 100">
<defs>
<path id="textPathTop" d={`
M 0 40
A 40,40 0 0 1 0,-40
A 40,40 0 0 1 0,40`}></path>
<path id="textPathBottom" d={`
M 0 -41.8
A 41.8,41.8 0 0 0 0,41.8
A 41.8,41.8 0 0 0 0,-41.8`}></path>
</defs>
<use xlinkHref="#textPathBottom" fill="none" stroke="red"></use>
<text fill="red" fontSize="4.5"><textPath xlinkHref="#textPathBottom">We go up, then we go down, then up again</textPath></text>
</svg>
</div>
This shows the "We go up, then we go down, then up again" text, but just in a straight horizontal line starting from 0,0.
Copying the resulting html into a codepen shows the result as it should look, using the textPath.
Why is the textPath ignored when rendered with ReactJS?
Using React 15.3.1 and checking in FF 52.0.2(32bit)
Already tried using _dangerouslySetInnerHTML for textPath, but that didn't work either.
Check if you have a <base href="..."> tag in your <head> element.
If so, Firefox won't be able to display your text, while Chrome will.
Firefox is searching for your xlink:href attribute at the base href url, it does not find it, so the text is just ignored.
A workaround is to use an absolute url :
<textPath xlink:href="http://pathtoyourpage#textPathBottom">
It is easier if you generate the svg with javascript :
textPath.setAttribute('xlink:href', `${location.href}#textPathBottom`)
Some similar weird behavior happen with mask and filter attributes.
I have the following SVG of a phone:
<svg width="897px" height="452px" viewBox="0 0 897 452" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<g id="iphone" sketch:type="MSLayerGroup" stroke="#7E89A3" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M130,257.964 C130,266.797 122.809,273.956 113.938,273.956 L16.063,273.956 C7.192,273.956 0.001,266.797 0.001,257.964 L0.001,16.073 C0.001,7.24 7.192,0.081 16.063,0.081 L113.938,0.081 C122.809,0.081 130,7.24 130,16.073 L130,257.964 L130,257.964 Z"
id="bezel" stroke-width="2" fill="white" sketch:type="MSShapeGroup"></path>
<rect id="screen" fill="#ddd"
sketch:type="MSShapeGroup" x="9" y="36" width="111.93" height="199.084"></rect>
<path d="M77,25.746 C77,26.381 76.561,26.893 76.02,26.893 L55.918,26.893 C55.376,26.893 54.938,26.38 54.938,25.746 L54.938,23.166 C54.938,22.531 55.377,22.019 55.918,22.019 L76.02,22.019 C76.561,22.019 77,22.532 77,23.166 L77,25.746 L77,25.746 Z" id="speaker"
sketch:type="MSShapeGroup"></path>
<circle id="camera" sketch:type="MSShapeGroup" cx="66" cy="12" r="3"></circle>
<ellipse id="lock" sketch:type="MSShapeGroup" cx="65.04" cy="254.001" rx="10.04" ry="10.001"></ellipse>
</g>
</svg>
Which looks like following:
I will be using AngularJS to dynamically generate <ul> with elements on the phone screen, where generated elements will be interactive (users will be able to e.g. click on them).
The challenge however is, how to lock the size of my div element (which will hold the ul element), so that it always has the size of the screen? I want this phone to be center aligned on my page, but as far as I know, the SVG size will adapt to the actual window size.
Is there a way how to dynamically poisition my div element to be only on the phone's screen?
P.S. I can see that my SVG contains element with id screen so maybe somehow detect the position of this element?
I would recommend placing an absolutely positioned div over the SVG element. You can calculate the dimensions of the screen image by using the getBoundingClientRect() method. The code is simple:
var ui = document.getElementById("ui");
var screen = document.getElementById("screen");
var dimensions = screen.getBoundingClientRect();
ui.style.left = dimensions.left + "px";
ui.style.top = dimensions.top + "px";
ui.style.width = dimensions.width + "px";
ui.style.height = dimensions.height + "px";
You can see a working example here: https://jsfiddle.net/hxe9nb3n/
For a start it doesn't have to adapt to the size of the window. That behaviour is under your control.
Alternatively, you can embed HTML inside an SVG using the <foreignObject> element. That way the embedded HTML will adapt to whatever size the SVG becomes. There are many examples of how to do that in SO.
I'm using a circular clip path for my nodes (in d3.js) as follows:
<g class="node" id="140" transform="translate(392.3261241288836,64.3699106556645)">
<image class="mainImage" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="images/manual-story-140.jpg" width="100" height="116.66705555685185" x="-50" y="-50" clip-path="url(#140)">
</image>
<clipPath class="clipPath" id="140">
<circle class="clipPathCircle" stroke-width="1" r="42"></circle>
</clipPath>
<circle class="outlinecircle" stroke="#0099FF" fill="url(#myLinearGradient1)" stroke-width="3" r="42"></circle>
</g>
But in Firefox the images don't load because the circle element within the clipPath element doesn't inherit the position of the node (i.e. from the g element).
In Chrome/Safari, everything works great and when I open up the console and hover over the circle element that's within the clipPath element it clearly shows the circle in the correct place (with dimensions of 84x84 since the radius is 42).
But in Firefox I see no images, and when I hover over the circle using the console I see it's positioned at the top left of the screen with dimensions 0x0.
Any ideas what I'm doing wrong here? Do I have to give an absolute position of the circle for firefox or should it already understand from the g-element it's in?
Apologies for the false alarm, but the problem here (as you can see in my original code) was that I was using the same id on my parent g element as I was to reference my clipPath! I changed the "id" attribute for my clip path to start with the string "clipPath-" and now it works on Firefox. Not sure why that would affect different browsers differently (which is why I kinda went 'round the houses trying to troubleshoot the bug), but thankfully enough it's quite a trivial fix!
I have a set of svg element
<svg id="container_svg" style="width: 700px; height: 600px;>
<rect width='600' height='600'> </rect>
<g>
<path d="M 285 0 L 285 0 L 318.34499999999997 57.5055 L 251.655 57.5055 z"/>
</g>
</svg>
and added a mousemove event to svg element in document.ready as
$("#container_svg").mousemove(function(evt){
var child=$(evt.target)[0].nodeName;
});
So moving on svg element, the event get triggered but getting different target element in different browser as below.
Even though moving on the path element in svg, i am getting $(evt.target)[0].nodeName as "rect" in firefox,
but in IE and chrome $(evt.target)[0].nodeName returns "path" as i want...
Thanks,
Siva
Cross browsers solution:
$("#container_svg *").mousemove(function(evt){
//var child=$(evt.target)[0].nodeName;
evt.stopPropagation();
var child=$(evt.currentTarget)[0].nodeName;
});
don't know why you down-voted my previews answer...