Move graphic SVG objects

Asked

Viewed 413 times

2

I want to draw up a graph where I can move the dots (circle) of a Javascript line. When moving the object circle, the line is always glued to the circle.

I want to play the genre of this:

inserir a descrição da imagem aqui

That is, it is a line for each circle, being possible to move them and get their positions.

The base graph is the following SVG, which is a kind of Cartesian plan:

<svg id="svg" width=100% height=500px >

    //vertical
    <line title="Vertical" x1=60 y1=60 x2=60 y2=450 stroke-width=2 stroke=black /> 

    //text vertical
    <text x=60 y=60 text-anchor=end fill=black ><?php echo $txtmaxresistance." Ohm";?></text>
    <text x=55 y=450 text-anchor=end fill=black ><?php echo $txtminresistance;?></text>

    //horizontal
    <line title="Horizontal" x1=60 y1=450 x2=450 y2=450 stroke-width=2 stroke=black /> 

    //text horizontal
    <text x=470 y=465 text-anchor=end fill=black ><?php echo $txtmaxtemp." Temp";?></text>
    <text x=80 y=465 text-anchor=end fill=black ><?php echo $txtmintemp;?></text>

    <line title=<?php echo $txtnome;?> x1=400 y1=90 x2=60 y2=450  stroke-width=2 stroke=black />    


</svg>

The following code creates the various circles (dots) on top of a straight line:

var svg = document.querySelector('svg');

        for (var i = 0; i < step; i++) {
            var x = 30*i;
            var y = 30*i;
            var shape = document.createElementNS("http://www.w3.org/2000/svg", "circle");
            shape.setAttributeNS(null, "cx", 100+x);
            shape.setAttributeNS(null, "cy", 400-y);
            shape.setAttributeNS(null, "r", 5);
            shape.setAttributeNS(null, "fill", "green");
            svg.appendChild(shape);
        }

1 answer

4


With some positioning adjustments in the graph, I made a simple implementation using pure Javascript, allowing drag and drop the vertices and making the line follow this movement.

See the implementation below:

var svg = document.querySelector('svg');

//data to control drag'n drop 
var ddData = {
    element: null,
    initialX: 0,
    initialY: 0, 
    originalX: 0,
    originalY: 0,
    lineEnd: null,
    lineStart: null
};

//number of dots on the line
var steps = 10, originX = 60, originY = 450;

//distance between circles
var stepX = (450 - 60) / (steps + 1);
var stepY = stepX;

//create lines
var lines = [];
for (var i = 0; i <= steps; i++) {
    var x1 = stepX * i, x2 = stepX * (i + 1);
    var y1 = stepY * i, y2 = stepY * (i + 1);
    
    var line = document.createElementNS( 
        "http://www.w3.org/2000/svg", "line");
    line.setAttributeNS(null, "x1", originX + x1);
    line.setAttributeNS(null, "y1", originY - y1);
    line.setAttributeNS(null, "x2", originX + x2);
    line.setAttributeNS(null, "y2", originY - y2);
    line.setAttributeNS(null, "stroke", "red");
    line.setAttributeNS(null, "stroke-width", "2");
    svg.appendChild(line);
    
    lines[i] = line;
}

//create dots
for (var i = 0; i < steps; i++) {
    var x = stepX * (i + 1);
    var y = stepY * (i + 1);
    
    //create circle
    var shape = document.createElementNS(
        "http://www.w3.org/2000/svg", "circle");
    shape.setAttributeNS(null, "cx", originX + x);
    shape.setAttributeNS(null, "cy", originY - y);
    shape.setAttributeNS(null, "r", 5);
    shape.setAttributeNS(null, "fill", "green");
    shape.setAttributeNS(null, "class", "draggable");
    shape.setAttributeNS(null, "order", i);
    svg.appendChild(shape);
    
    //start moving circle
    shape.onmousedown = function(evt) {
        var evt = evt || window.event;
        ddData.element = evt.target || evt.srcElement;
        ddData.initialX = evt.clientX;
        ddData.initialY = evt.clientY;
        ddData.originalX = parseFloat(
            ddData.element.getAttributeNS(null, "cx"));
        ddData.originalY = parseFloat(
            ddData.element.getAttributeNS(null, "cy"));
        var order = parseInt(
            ddData.element.getAttributeNS(null, "order"));
        ddData.lineEnd = lines[order];
        ddData.lineStart = lines[order+1];
    };
}

//handle mouse movement to drag circles
svg.onmousemove = function(evt) {
    var evt = evt || window.event;
    if (ddData.element) {
        var posX = ddData.originalX + evt.clientX - ddData.initialX;
        var posY = ddData.originalY + evt.clientY - ddData.initialY;
        //move object
        ddData.element.setAttributeNS(null, "cx", posX);
        ddData.element.setAttributeNS(null, "cy", posY);
        //move line before
        ddData.lineEnd.setAttributeNS(null, "x2", posX);
        ddData.lineEnd.setAttributeNS(null, "y2", posY);
        //move line after
        ddData.lineStart.setAttributeNS(null, "x1", posX);
        ddData.lineStart.setAttributeNS(null, "y1", posY);
    }
};

//stops drag movement
svg.onmouseup = function(evt) {
    var evt = evt || window.event;
    ddData.element = null;
}
.draggable {
    cursor: move;
}
<svg id="svg" width=100% height=500px >
    <line title="Vertical" x1=60 y1=60 x2=60 y2=450 stroke-width=2 stroke=black /> 
    <text x=60 y=60 text-anchor=end fill=black >10 Ohm</text>
    <text x=55 y=450 text-anchor=end fill=black >12</text>

    <line title="Horizontal" x1=60 y1=450 x2=450 y2=450 stroke-width=2 stroke=black /> 
    <text x=470 y=465 text-anchor=end fill=black >100 Temp</text>
    <text x=80 y=465 text-anchor=end fill=black >1</text>

    <line title="Teste" x1=450 y1=60 x2=60 y2=450  stroke-width=2 stroke=black />    
</svg>

The code is kind of large to explain in detail, but I left some comments in the middle of it and I hope it’s easy to read.

I got an idea or two of this link. See also a more advanced example with curved lines using the library D3.

  • Thank you, good code. How can I get the position of each of the points now?

  • @akm Just retrieve a reference to the object created in some way and use the snippet parseFloat(ponto.getAttributeNS(null, "cx")). Do the same for the position cy.

  • I am using var x=parseFloat(ddData.element.getAttributeNS(null, "Cx")); within onmousemove function.

  • @akm Inside the function works because the ddData.element has reference to the clicked circle. If you want to recover the position of other circles or of all of them, you have to recover these references from somewhere else. I don’t know what you want it for exactly, but a simple idea is to store all the circles in one vector, then you can make a loop and retrieve the position of each one.

  • Yes I want to recover the position of all the circles, then save their position x and y after moving in a file.

  • How can I take the lines from the beginning and the end? I changed the for, to step-2. I want 10 circles and 8 lines.

  • How can I recover the positions of the other circles?

Show 2 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.