i'm using Highcharts , the chart result is a collection of SVG elements and i was trying to add some elements to this SVG using jquery
Here is what i have tried
function(chart) { // on chart load complete
$("#highcharts-0 Svg").
append(document.createElementNS("http://www.w3.org/2000/svg", "rect"));
$("#highcharts-0 Svg").find("rect").
attr({x : 100 , y:100 , width : 100 , height : 100 });
console.log($("#highcharts-0 Svg "));
});
i can't really say if this is working or not , all i can see is a <rect></rect> element in my DOM with no attr
another notice is when i hover on this element using chrome console it shows the rec on x-0 , y=0,
i have an idea that jquery does not append svg elements hop i'm wrong
Question How can i add element with attributes to SVG using jquery
EDIT
with help now i have id for the rect element
then i tried to add attr with using the id , but failed
ScreenShot
Highcharts also has a drawing API that you can use to draw rectangles. This works also for VML. Check out http://www.highcharts.com/ref/#renderer => rect and live sample at http://jsfiddle.net/gh/get/jquery/1.7.1/highslide-software/highcharts.com/tree/master/samples/highcharts/members/renderer-rect-on-chart/.
As you can see here, there're no attributes rx and ry, try to change it to x and y.
Rectangles have x and y attributes. rx and ry are used on circles.
Also, are you sure your selector is correct? You might want to lowercase the 'Svg'
** edit **
The rect in your screenshot doesn't have any of the attributes assigned. There's no width or height, or x/y positions. You should try giving the rectangle an id when appending it, and querying for it using that same id.
See:
https://developer.mozilla.org/en/DOM/document.createElementNS
You can do it like this:
var rect = document.createElementNS("http://www.w3.org/2000/svg","rect");
rect.id = 'your_id_here';
Then append the rect through the normal route.
Note that, since you have the raw dom element, you might be able to assign your other properties there as well. e.g.:
rect.x = 100;
rect.y = 100;
rect.fill = 'blue';
Related
I have a bit of an annoying problem.
I'm trying to position a bunch of SVG circle elements according to an existing bunch of SVG text elements that share similar properties.
The circle elements are created in a very separate process than the text elements, so positioning the new elements just using the same transforms etc. as the old one isn't a viable option.
I'm trying to use .getBoundingClientRect() to get the positions since the text elements are transformed into position (so .getBBox() isn't an option) rather than positioned by x and y attributes.
With .getBoundingClientRect(), I can get the correct size/arrangement of the new elements, but since the width of the svg-containing div is variable, there's always a bit of a weird offset that I can't quite account for.
I created a simplified example of my issue here. Resize and refresh the page to see the issue in action.
The code I use to position the circle elements is replicated below.
var circs = theSvg.selectAll("circle")
.data(theCircles)
.enter()
.append("circle")
.attr("r", 15)
.attr("fill", "#f00")
.style("opacity", 0.3)
.attr("transform", function(d){
var sizeDif = 800/(d3.select(".svgTestHolder")[0][0].getBoundingClientRect()["width"]);
var theNum = parseInt(d.split("&")[1]);
var thePosition = theSvg.selectAll("text").filter(function(e){
return e == theNum;})[0];
var theCoords = thePosition[0].getBoundingClientRect();
var leftOffset = d3.select(".svgTestHolder")[0][0].getBoundingClientRect()["left"];
var leftOffset2 = d3.select(".svgTest")[0][0].getBoundingClientRect()["left"];
var bottomOffset = d3.select(".svgTestHolder")[0][0].getBoundingClientRect()["top"];
var bottomOffset2 = d3.select(".svgTest")[0][0].getBoundingClientRect()["top"];
return
"translate(" + ((theCoords["left"] - leftOffset - leftOffset2)
* sizeDif) + "," + ((theCoords["top"] - bottomOffset - bottomOffset2)
* sizeDif) + ")";
})
EDIT:
This is a very delayed update just to note that while I was unable to answer my question as stated, I was able to make a workable solution based on Paul LeBeau's suggestion to extract the transforms from the target element.
In my case, I had to use a series of consecutive transforms rather than a combination of transforming and changing the x/y position (due to certain realities of the project not represented in the linked example). But I'm happy to have found an answer!
Your example works fine for me on Chrome. But really that's only because the SVG is the only thing on the page. If I add some text above the SVG everything goes wrong.
https://jsfiddle.net/rrpfmm6d/1/
Is this the problem you are talking about?
If so, the reason is because you are making the wrong choice in using getBoundingClientRect(). It provides coordinates in screen space. It's origin is the top left of the window (or iframe in the case of jsfiddle).
You should be using getBBox(). The values it returns are in the same coordinate space as the SVG elements. It's origin is (normally) at the top left of the SVG.
In summary, use the coordinates returned by calling getBBox() on your <text> element to calculate the position for your circle. If the circles are inserted into the same SVG as the text, there will be no need to do any adjusting with the div or svg offsets.
Here I have a JSFiddle:
'http://jsfiddle.net/reko91/66m1q9g2/'
I made a function to make circles. Now in this function I have to select an area which to append my circle :
var circle = d3.select("#" + area)
.append("svg:circle");
Now I draw two circles :
createCircle("svg", 100,100,50,"red"); // here i select the SVG - it works
createCircle("canvas", 200,200,50,"green"); // here i select the canvas - doesnt work
When I append the circle to the SVG i created it works, but not when I append it to the canvas i made.
What stupid mistake have i made ?
An SVG <rect> element is not a container and cannot be the parent of another <rect> or <circle> element. Make the second circle a sibling of the first.
I am creating a rectangle element in raphael JS as a tooltip on an SVG circle element generated by raphael JS. I am unable to access the coordinates of the center of the circle (which I need to place the rectangle tooltip) using the following code in Internet Explorer..
var c = {};
c.x = parseInt(c_element.node.attributes[0].nodeValue);
c.y = parseInt(c_element.node.attributes[1].nodeValue);
//code for the rectangle element tooltip
r = paper.rect(c.x,c.y,50,50);
Its working fine in Firefox.. But in IE, the tooltip gets created at the upper left corner of the div enclosing my raphael JS paper and not on the center o the circle as desired..
How do I solve this cross-browser issue? Please help..
I don't know for certain why IE doesn't like this, but there's a much easier way:
c.x = c_element.attr("cx");
c.y = c_element.attr("cy");
jsFiddle
If you log the Raphael object to the console, you can check out the "attrs" property to see what's in there. Different for every type of Raphael object.
While we're all here: I highly recommend using an absolutely positioned div for your tooltips. HTML handles things like wrapping text and resizing the tooltip to accomodate different amounts of text much more easily than the SVG text element. See this answer. (Whatever you use, you'll still need to access the coordinates of the circle.)
I expected this to be 100% a no-brainer, but as it turns out, I cannot figure out what the x and y attributes of an svg created and manipulated with Raphael.js mean. I assumed they were the coordinates of the top-left corner of the object in relation to the canvas, but now I'm not so sure.
After creating a canvas (var paper = new Raphael(container,width,height)) and adding an image or rectangle to it, for example, if I retrieve the "x" and "y" attributes using the attr method (e.g. object.attr("x")), they're both at 0. However, if I rotate that object and then retrieve the values of x and y again, the values don't reflect the position of the top-left corner of my object in relation to the canvas anymore.
Can someone please explain this to me?
I fear #afaf12's answer complacently goes only half the distance. He's absolutely correct that transformation logic occurs after the fundamental attributes of a given element and doesn't effect them, but it is certainly possible to retrieve the x and y of that element after transformations are applied. You'll want to use the getBBox method, like this:
var bbox = elem.getBBox();
console.log("Transformed coordinates of element are %s,%s", bbox.x, bbox.y );
Please note that there is some trickiness involved -- this returns the bounding box of the element, which is often a superset of the space occupied by the element -- so there's no guarantee that the returned point will be IN the element.
Another alternative occurs if you're using paths -- path.getPointAtLength also works with transformed coordinates, so you can get the x,y offset of the beginning of a path by calling
var coord = elem.getPointAtLength(0);
console.log("Transformed coordinates of path are %s,%s", coord.x, coord.y );
Rotation is a transformation and it does not change x and y of the object.
http://raphaeljs.com/reference.html#Element.transform
I'm using Raphael.js to produce an SVG drawing from Javascript (actually Coffeescript)
However, I'd like to be able to include subdrawings, automatically scaled, by putting them inside a second <svg> tag nested inside the first. Unfortunately the Raphael Paper object which allows me to add rects and paths etc. doesn't have an option for adding svgs.
I've tried to add the tag directly to the DOM in javascript with the following code :
res = document.createElement("svg")
res.setAttribute("x",x)
res.setAttribute("y",y)
res.setAttribute("width",width)
res.setAttribute("height",height)
res.setAttribute("viewBox","0 0 100 100")
res.innerHTML = someInnerSVG
#paper.canvas.appendChild(res)
This seems to update the DOM as expected, adding my new SVG tag as a child of the main outer SVG. However, nothing in this inner actually appears on the screen. (My inner SVG path is scaled within 0 0 100 100 so is within the viewBox.)
The rest of the drawing in the outer SVG, as produced by Raphael, is visible. But nothing of the inner one is.
Should what I'm trying be possible? Any idea what I'm doing wrong?
You should place these sub elements into a Raphael set. From there, you will be able to apply transformations to the set. To transform the set, you would call the transform() method and use the s attribute:
set.transform('s[sx],[sy]');
Where sx is the horizontal scale amount and sy is the vertical scale amount. Remove the brackets when you insert the numbers.
Please refer to the documentation here: http://raphaeljs.com/reference.html#Element.transform
The methods for elements apply to sets because sets are pseudo elements.