Question

I need to add the circle in the svg dynamically. Here its adding to the svg correctly but not in the correct position. Here i create on circle inside the svg and get the x and y position by clicking on the svg to add the new circle. Its getting the clientX and clientY position correctly from the screen but the newly adding circle is not correctly adding to the correct position. I need to add the new circle on the svg on the selected position .

Here is the DEMO.

var xpos, ypos;
$("svg").click(function (e) {
    xpos = e.clientX;
    ypos = e.clientY;
    alert(xpos+' '+ypos);
});

$("#create").click(function (e) {
    var svgNS = "http://www.w3.org/2000/svg";
    var myCircle = document.createElementNS(svgNS, "circle");
    myCircle.setAttributeNS(null, "id", "mycircle");
    myCircle.setAttributeNS(null, "fill", 'blue');
    myCircle.setAttributeNS(null, "cx", xpos);
    myCircle.setAttributeNS(null, "cy", ypos);
    myCircle.setAttributeNS(null, "r", '6');
    myCircle.setAttributeNS(null, "stroke", "none");
    var svg = document.querySelector("svg");
    svg.appendChild(myCircle);
});

any suggestions should be appreciated.

Was it helpful?

Solution

Something like this should do it.

$("#create").click(function (e) {
    var svgNS = "http://www.w3.org/2000/svg";
    var myCircle = document.createElementNS(svgNS, "circle");
    myCircle.setAttributeNS(null, "id", "mycircle");
    myCircle.setAttributeNS(null, "fill", 'blue');
    myCircle.setAttributeNS(null, "r", '6');
    myCircle.setAttributeNS(null, "stroke", "none");
    var svg = document.querySelector("svg");
    svg.appendChild(myCircle);
    var pt = svg.createSVGPoint();
    pt.x = xpos;
    pt.y = ypos;
    var globalPoint = pt.matrixTransform(myCircle.getScreenCTM().inverse());
    var globalToLocal = myCircle.getTransformToElement(svg).inverse();
    var inObjectSpace = globalPoint.matrixTransform(globalToLocal);
    myCircle.setAttributeNS(null, "cx", inObjectSpace.x);
    myCircle.setAttributeNS(null, "cy", inObjectSpace.y);
});

This question has more details. although its solution is not quite right.

OTHER TIPS

The problem is coming from two things:

  1. e.clientX and e.clientY are the position in the page. Hence not totally relevant the inside of the svg. To make that a valuable information, let's use jQuery offset. That gives the following coordinate in pixels:

    var offset = $(this).offset();
    xpos = e.clientX - offset.left;
    ypos = e.clientY - offset.top;
    
  2. The other problem comes from the way viewport and svg positioning interract. The fact is, with your settings we have a box of 200px*200px in which has the top left corner as the coordinate 0,-100 and the bottom right is 400,300.

    To solve your problem, the solution I used is the following: adding a white rectangle in the background (this way the svg is effectively using all the space we're giving it). And use a slight translation to adjust to the svg coordinate, which is

    xpos = (e.clientX - offset.left)*2;
    ypos = (e.clientY - offset.top)*2 - 100;
    

See the updated fiddle here

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top