Resetting drag with multiple elementsHow do I detect a click outside an element?How do I check if an element is hidden in jQuery?Event binding on dynamically created elements?Creating a div element in jQueryHow can I select an element with multiple classes in jQuery?How to move an element into another element?Check if element exists in jQueryHow do I remove a particular element from an array in JavaScript?jQuery scroll to elementD3 drag event behaviour: DragEvent.x and DragEvent.y values source

Phase portrait of a system of differential equations

A wiild aanimal, a cardinal direction, or a place by the water

Where can I see modifications made to the PATH environment variable by the Go installer

How to call made-up data?

Have you been refused entry into the Federal Republic of Germany?

What is the most 'environmentally friendly' way to learn to fly?

Why does BezierFunction not follow BezierCurve at npts>4?

What is Albrecht Dürer's Perspective Machine drawing style?

Meaning of ギャップ in the following sentence

Can I say "Gesundheit" if someone is coughing?

How were x-ray diffraction patterns deciphered before computers?

Is law enforcement responsible for damages made by a search warrant?

Difference between "jail" and "prison" in German

Subverting the essence of fictional and/or religious entities; is it acceptable?

How long should I wait to plug in my refrigerator after unplugging it?

How can I perform a deterministic physics simulation?

Does a bard know when a character uses their Bardic Inspiration?

(7 of 11: Fillomino) What is Pyramid Cult's Favorite Shape?

What is the reason behind water not falling from a bucket at the top of loop?

Is there a word that describes people who are extraverted and/or energetic, but uneducated, unintelligent and/or uncreative?

Has J.J.Jameson ever found out that Peter Parker is Spider-Man?

Can birds evolve without trees?

characteristic of ring

Can an unintentional murderer leave Ir Miklat for Shalosh Regalim?



Resetting drag with multiple elements


How do I detect a click outside an element?How do I check if an element is hidden in jQuery?Event binding on dynamically created elements?Creating a div element in jQueryHow can I select an element with multiple classes in jQuery?How to move an element into another element?Check if element exists in jQueryHow do I remove a particular element from an array in JavaScript?jQuery scroll to elementD3 drag event behaviour: DragEvent.x and DragEvent.y values source






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








2















I have multiple svg groups (each containing a circle and text) which I am dragging via d3-drag from an initial position. I have a rectangular hit zone that I only want one of these draggable groups in at a time. So whenever two groups are in the hit zone, I would like the first group that was in the hit zone to fade away and reappear in its initial position.



I have tried doing this via a function which translates the group back to its initial position by finding the current position of the circle shape and translating like:



translate($-current_x, $-current_y)


This does translate the group back to the (0,0) position, so I have to offset by its initial position. I do this by setting the initial x and y values of the circle shape as attributes in the circle element and incorporating these into the translation:



translate($-current_x + initial_x, $-current_y + initial_y)


Here is a block of my attempt:



https://bl.ocks.org/interwebjill/fb9b0d648df769ed72aeb2755d3ff7d5



And here it is in snippet form:






 const circleRadius = 40;
const variables = ['one', 'two', 'three', 'four'];
const inZone = [];

// DOM elements
const svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 500)

const dragDockGroup = svg.append('g')
.attr('id', 'draggables-dock');

const dock = dragDockGroup.selectAll('g')
.data(variables)
.enter().append("g")
.attr("id", (d, i) => `dock-$variables[i]`);

dock.append("circle")
.attr("cx", (d, i) => circleRadius * (2 * i + 1))
.attr("cy", circleRadius)
.attr("r", circleRadius)
.style("stroke", "none")
.style("fill", "palegoldenrod");

dock.append("text")
.attr("x", (d, i) => circleRadius * (2 * i + 1))
.attr("y", circleRadius)
.attr("text-anchor", "middle")
.style("fill", "white")
.text((d, i) => variables[i]);

const draggablesGroup = svg.append('g')
.attr('id', 'draggables');

const draggables = draggablesGroup.selectAll('g')
.data(variables)
.enter().append("g")
.attr("id", (d, i) => variables[i])
.call(d3.drag()
.on("start", dragStarted)
.on("drag", dragged)
.on("end", dragEnded));

draggables.append('circle')
.attr("cx", (d, i) => circleRadius * (2 * i + 1))
.attr("cy", circleRadius)
.attr("initial_x", (d, i) => circleRadius * (2 * i + 1))
.attr("initial_y", circleRadius)
.attr("r", circleRadius)
.style("stroke", "orange")
.style("fill", "yellowgreen");

draggables.append("text")
.attr("x", (d, i) => circleRadius * (2 * i + 1))
.attr("y", circleRadius)
.attr("text-anchor", "middle")
.style("fill", "white")
.text((d, i) => variables[i]);

svg.append('rect')
.attr("x", 960/2)
.attr("y", 0)
.attr("width", 100)
.attr("height", 500/2)
.attr("fill-opacity", 0)
.style("stroke", "#848276")
.attr("id", "hitZone");

// functions
function dragStarted()
d3.select(this).raise().classed("active", true);


function dragged()
d3.select(this).select("text").attr("x", d3.event.x).attr("y", d3.event.y);
d3.select(this).select("circle").attr("cx", d3.event.x).attr("cy", d3.event.y);


function dragEnded()
d3.select(this).classed("active", false);
d3.select(this).lower();
let hit = d3.select(document.elementFromPoint(d3.event.sourceEvent.clientX, d3.event.sourceEvent.clientY)).attr("id");

if (hit == "hitZone")
inZone.push(this.id);
if (inZone.length > 1)
let resetVar = inZone.shift();
resetCircle(resetVar);



d3.select(this).raise();


function resetCircle(resetVar)
let current_x = d3.select(`#$resetVar`)
.select('circle')
.attr('cx');

let current_y = d3.select(`#$resetVar`)
.select('circle')
.attr('cy');

let initial_x = d3.select(`#$resetVar`)
.select('circle')
.attr('initial_x');

let initial_y = d3.select(`#$resetVar`)
.select('circle')
.attr('initial_y');

d3.select(`#$resetVar`)
.transition()
.duration(2000)
.style('opacity', 0)
.transition()
.duration(2000)
.attr('transform', `translate($-current_x, $-current_y)`)
.transition()
.duration(2000)
.style('opacity', 1);

 body margin:0;position:fixed;top:0;right:0;bottom:0;left:0; 

 <script src="https://d3js.org/d3.v5.min.js"></script>





Here are the problems:



  1. While using translate($-current_x, $-current_y) works, when I try using translate($-current_x + initial_x, $-current_y + initial_y), the translation uses very large negative numbers (for example, translate(-52640, -4640)).


  2. While using translate($-current_x, $-current_y) works, when I try to drag this translated group again, the group immediately repeats the previous translate($-current_x, $-current_y)










share|improve this question
































    2















    I have multiple svg groups (each containing a circle and text) which I am dragging via d3-drag from an initial position. I have a rectangular hit zone that I only want one of these draggable groups in at a time. So whenever two groups are in the hit zone, I would like the first group that was in the hit zone to fade away and reappear in its initial position.



    I have tried doing this via a function which translates the group back to its initial position by finding the current position of the circle shape and translating like:



    translate($-current_x, $-current_y)


    This does translate the group back to the (0,0) position, so I have to offset by its initial position. I do this by setting the initial x and y values of the circle shape as attributes in the circle element and incorporating these into the translation:



    translate($-current_x + initial_x, $-current_y + initial_y)


    Here is a block of my attempt:



    https://bl.ocks.org/interwebjill/fb9b0d648df769ed72aeb2755d3ff7d5



    And here it is in snippet form:






     const circleRadius = 40;
    const variables = ['one', 'two', 'three', 'four'];
    const inZone = [];

    // DOM elements
    const svg = d3.select("body").append("svg")
    .attr("width", 960)
    .attr("height", 500)

    const dragDockGroup = svg.append('g')
    .attr('id', 'draggables-dock');

    const dock = dragDockGroup.selectAll('g')
    .data(variables)
    .enter().append("g")
    .attr("id", (d, i) => `dock-$variables[i]`);

    dock.append("circle")
    .attr("cx", (d, i) => circleRadius * (2 * i + 1))
    .attr("cy", circleRadius)
    .attr("r", circleRadius)
    .style("stroke", "none")
    .style("fill", "palegoldenrod");

    dock.append("text")
    .attr("x", (d, i) => circleRadius * (2 * i + 1))
    .attr("y", circleRadius)
    .attr("text-anchor", "middle")
    .style("fill", "white")
    .text((d, i) => variables[i]);

    const draggablesGroup = svg.append('g')
    .attr('id', 'draggables');

    const draggables = draggablesGroup.selectAll('g')
    .data(variables)
    .enter().append("g")
    .attr("id", (d, i) => variables[i])
    .call(d3.drag()
    .on("start", dragStarted)
    .on("drag", dragged)
    .on("end", dragEnded));

    draggables.append('circle')
    .attr("cx", (d, i) => circleRadius * (2 * i + 1))
    .attr("cy", circleRadius)
    .attr("initial_x", (d, i) => circleRadius * (2 * i + 1))
    .attr("initial_y", circleRadius)
    .attr("r", circleRadius)
    .style("stroke", "orange")
    .style("fill", "yellowgreen");

    draggables.append("text")
    .attr("x", (d, i) => circleRadius * (2 * i + 1))
    .attr("y", circleRadius)
    .attr("text-anchor", "middle")
    .style("fill", "white")
    .text((d, i) => variables[i]);

    svg.append('rect')
    .attr("x", 960/2)
    .attr("y", 0)
    .attr("width", 100)
    .attr("height", 500/2)
    .attr("fill-opacity", 0)
    .style("stroke", "#848276")
    .attr("id", "hitZone");

    // functions
    function dragStarted()
    d3.select(this).raise().classed("active", true);


    function dragged()
    d3.select(this).select("text").attr("x", d3.event.x).attr("y", d3.event.y);
    d3.select(this).select("circle").attr("cx", d3.event.x).attr("cy", d3.event.y);


    function dragEnded()
    d3.select(this).classed("active", false);
    d3.select(this).lower();
    let hit = d3.select(document.elementFromPoint(d3.event.sourceEvent.clientX, d3.event.sourceEvent.clientY)).attr("id");

    if (hit == "hitZone")
    inZone.push(this.id);
    if (inZone.length > 1)
    let resetVar = inZone.shift();
    resetCircle(resetVar);



    d3.select(this).raise();


    function resetCircle(resetVar)
    let current_x = d3.select(`#$resetVar`)
    .select('circle')
    .attr('cx');

    let current_y = d3.select(`#$resetVar`)
    .select('circle')
    .attr('cy');

    let initial_x = d3.select(`#$resetVar`)
    .select('circle')
    .attr('initial_x');

    let initial_y = d3.select(`#$resetVar`)
    .select('circle')
    .attr('initial_y');

    d3.select(`#$resetVar`)
    .transition()
    .duration(2000)
    .style('opacity', 0)
    .transition()
    .duration(2000)
    .attr('transform', `translate($-current_x, $-current_y)`)
    .transition()
    .duration(2000)
    .style('opacity', 1);

     body margin:0;position:fixed;top:0;right:0;bottom:0;left:0; 

     <script src="https://d3js.org/d3.v5.min.js"></script>





    Here are the problems:



    1. While using translate($-current_x, $-current_y) works, when I try using translate($-current_x + initial_x, $-current_y + initial_y), the translation uses very large negative numbers (for example, translate(-52640, -4640)).


    2. While using translate($-current_x, $-current_y) works, when I try to drag this translated group again, the group immediately repeats the previous translate($-current_x, $-current_y)










    share|improve this question




























      2












      2








      2


      1






      I have multiple svg groups (each containing a circle and text) which I am dragging via d3-drag from an initial position. I have a rectangular hit zone that I only want one of these draggable groups in at a time. So whenever two groups are in the hit zone, I would like the first group that was in the hit zone to fade away and reappear in its initial position.



      I have tried doing this via a function which translates the group back to its initial position by finding the current position of the circle shape and translating like:



      translate($-current_x, $-current_y)


      This does translate the group back to the (0,0) position, so I have to offset by its initial position. I do this by setting the initial x and y values of the circle shape as attributes in the circle element and incorporating these into the translation:



      translate($-current_x + initial_x, $-current_y + initial_y)


      Here is a block of my attempt:



      https://bl.ocks.org/interwebjill/fb9b0d648df769ed72aeb2755d3ff7d5



      And here it is in snippet form:






       const circleRadius = 40;
      const variables = ['one', 'two', 'three', 'four'];
      const inZone = [];

      // DOM elements
      const svg = d3.select("body").append("svg")
      .attr("width", 960)
      .attr("height", 500)

      const dragDockGroup = svg.append('g')
      .attr('id', 'draggables-dock');

      const dock = dragDockGroup.selectAll('g')
      .data(variables)
      .enter().append("g")
      .attr("id", (d, i) => `dock-$variables[i]`);

      dock.append("circle")
      .attr("cx", (d, i) => circleRadius * (2 * i + 1))
      .attr("cy", circleRadius)
      .attr("r", circleRadius)
      .style("stroke", "none")
      .style("fill", "palegoldenrod");

      dock.append("text")
      .attr("x", (d, i) => circleRadius * (2 * i + 1))
      .attr("y", circleRadius)
      .attr("text-anchor", "middle")
      .style("fill", "white")
      .text((d, i) => variables[i]);

      const draggablesGroup = svg.append('g')
      .attr('id', 'draggables');

      const draggables = draggablesGroup.selectAll('g')
      .data(variables)
      .enter().append("g")
      .attr("id", (d, i) => variables[i])
      .call(d3.drag()
      .on("start", dragStarted)
      .on("drag", dragged)
      .on("end", dragEnded));

      draggables.append('circle')
      .attr("cx", (d, i) => circleRadius * (2 * i + 1))
      .attr("cy", circleRadius)
      .attr("initial_x", (d, i) => circleRadius * (2 * i + 1))
      .attr("initial_y", circleRadius)
      .attr("r", circleRadius)
      .style("stroke", "orange")
      .style("fill", "yellowgreen");

      draggables.append("text")
      .attr("x", (d, i) => circleRadius * (2 * i + 1))
      .attr("y", circleRadius)
      .attr("text-anchor", "middle")
      .style("fill", "white")
      .text((d, i) => variables[i]);

      svg.append('rect')
      .attr("x", 960/2)
      .attr("y", 0)
      .attr("width", 100)
      .attr("height", 500/2)
      .attr("fill-opacity", 0)
      .style("stroke", "#848276")
      .attr("id", "hitZone");

      // functions
      function dragStarted()
      d3.select(this).raise().classed("active", true);


      function dragged()
      d3.select(this).select("text").attr("x", d3.event.x).attr("y", d3.event.y);
      d3.select(this).select("circle").attr("cx", d3.event.x).attr("cy", d3.event.y);


      function dragEnded()
      d3.select(this).classed("active", false);
      d3.select(this).lower();
      let hit = d3.select(document.elementFromPoint(d3.event.sourceEvent.clientX, d3.event.sourceEvent.clientY)).attr("id");

      if (hit == "hitZone")
      inZone.push(this.id);
      if (inZone.length > 1)
      let resetVar = inZone.shift();
      resetCircle(resetVar);



      d3.select(this).raise();


      function resetCircle(resetVar)
      let current_x = d3.select(`#$resetVar`)
      .select('circle')
      .attr('cx');

      let current_y = d3.select(`#$resetVar`)
      .select('circle')
      .attr('cy');

      let initial_x = d3.select(`#$resetVar`)
      .select('circle')
      .attr('initial_x');

      let initial_y = d3.select(`#$resetVar`)
      .select('circle')
      .attr('initial_y');

      d3.select(`#$resetVar`)
      .transition()
      .duration(2000)
      .style('opacity', 0)
      .transition()
      .duration(2000)
      .attr('transform', `translate($-current_x, $-current_y)`)
      .transition()
      .duration(2000)
      .style('opacity', 1);

       body margin:0;position:fixed;top:0;right:0;bottom:0;left:0; 

       <script src="https://d3js.org/d3.v5.min.js"></script>





      Here are the problems:



      1. While using translate($-current_x, $-current_y) works, when I try using translate($-current_x + initial_x, $-current_y + initial_y), the translation uses very large negative numbers (for example, translate(-52640, -4640)).


      2. While using translate($-current_x, $-current_y) works, when I try to drag this translated group again, the group immediately repeats the previous translate($-current_x, $-current_y)










      share|improve this question
















      I have multiple svg groups (each containing a circle and text) which I am dragging via d3-drag from an initial position. I have a rectangular hit zone that I only want one of these draggable groups in at a time. So whenever two groups are in the hit zone, I would like the first group that was in the hit zone to fade away and reappear in its initial position.



      I have tried doing this via a function which translates the group back to its initial position by finding the current position of the circle shape and translating like:



      translate($-current_x, $-current_y)


      This does translate the group back to the (0,0) position, so I have to offset by its initial position. I do this by setting the initial x and y values of the circle shape as attributes in the circle element and incorporating these into the translation:



      translate($-current_x + initial_x, $-current_y + initial_y)


      Here is a block of my attempt:



      https://bl.ocks.org/interwebjill/fb9b0d648df769ed72aeb2755d3ff7d5



      And here it is in snippet form:






       const circleRadius = 40;
      const variables = ['one', 'two', 'three', 'four'];
      const inZone = [];

      // DOM elements
      const svg = d3.select("body").append("svg")
      .attr("width", 960)
      .attr("height", 500)

      const dragDockGroup = svg.append('g')
      .attr('id', 'draggables-dock');

      const dock = dragDockGroup.selectAll('g')
      .data(variables)
      .enter().append("g")
      .attr("id", (d, i) => `dock-$variables[i]`);

      dock.append("circle")
      .attr("cx", (d, i) => circleRadius * (2 * i + 1))
      .attr("cy", circleRadius)
      .attr("r", circleRadius)
      .style("stroke", "none")
      .style("fill", "palegoldenrod");

      dock.append("text")
      .attr("x", (d, i) => circleRadius * (2 * i + 1))
      .attr("y", circleRadius)
      .attr("text-anchor", "middle")
      .style("fill", "white")
      .text((d, i) => variables[i]);

      const draggablesGroup = svg.append('g')
      .attr('id', 'draggables');

      const draggables = draggablesGroup.selectAll('g')
      .data(variables)
      .enter().append("g")
      .attr("id", (d, i) => variables[i])
      .call(d3.drag()
      .on("start", dragStarted)
      .on("drag", dragged)
      .on("end", dragEnded));

      draggables.append('circle')
      .attr("cx", (d, i) => circleRadius * (2 * i + 1))
      .attr("cy", circleRadius)
      .attr("initial_x", (d, i) => circleRadius * (2 * i + 1))
      .attr("initial_y", circleRadius)
      .attr("r", circleRadius)
      .style("stroke", "orange")
      .style("fill", "yellowgreen");

      draggables.append("text")
      .attr("x", (d, i) => circleRadius * (2 * i + 1))
      .attr("y", circleRadius)
      .attr("text-anchor", "middle")
      .style("fill", "white")
      .text((d, i) => variables[i]);

      svg.append('rect')
      .attr("x", 960/2)
      .attr("y", 0)
      .attr("width", 100)
      .attr("height", 500/2)
      .attr("fill-opacity", 0)
      .style("stroke", "#848276")
      .attr("id", "hitZone");

      // functions
      function dragStarted()
      d3.select(this).raise().classed("active", true);


      function dragged()
      d3.select(this).select("text").attr("x", d3.event.x).attr("y", d3.event.y);
      d3.select(this).select("circle").attr("cx", d3.event.x).attr("cy", d3.event.y);


      function dragEnded()
      d3.select(this).classed("active", false);
      d3.select(this).lower();
      let hit = d3.select(document.elementFromPoint(d3.event.sourceEvent.clientX, d3.event.sourceEvent.clientY)).attr("id");

      if (hit == "hitZone")
      inZone.push(this.id);
      if (inZone.length > 1)
      let resetVar = inZone.shift();
      resetCircle(resetVar);



      d3.select(this).raise();


      function resetCircle(resetVar)
      let current_x = d3.select(`#$resetVar`)
      .select('circle')
      .attr('cx');

      let current_y = d3.select(`#$resetVar`)
      .select('circle')
      .attr('cy');

      let initial_x = d3.select(`#$resetVar`)
      .select('circle')
      .attr('initial_x');

      let initial_y = d3.select(`#$resetVar`)
      .select('circle')
      .attr('initial_y');

      d3.select(`#$resetVar`)
      .transition()
      .duration(2000)
      .style('opacity', 0)
      .transition()
      .duration(2000)
      .attr('transform', `translate($-current_x, $-current_y)`)
      .transition()
      .duration(2000)
      .style('opacity', 1);

       body margin:0;position:fixed;top:0;right:0;bottom:0;left:0; 

       <script src="https://d3js.org/d3.v5.min.js"></script>





      Here are the problems:



      1. While using translate($-current_x, $-current_y) works, when I try using translate($-current_x + initial_x, $-current_y + initial_y), the translation uses very large negative numbers (for example, translate(-52640, -4640)).


      2. While using translate($-current_x, $-current_y) works, when I try to drag this translated group again, the group immediately repeats the previous translate($-current_x, $-current_y)






       const circleRadius = 40;
      const variables = ['one', 'two', 'three', 'four'];
      const inZone = [];

      // DOM elements
      const svg = d3.select("body").append("svg")
      .attr("width", 960)
      .attr("height", 500)

      const dragDockGroup = svg.append('g')
      .attr('id', 'draggables-dock');

      const dock = dragDockGroup.selectAll('g')
      .data(variables)
      .enter().append("g")
      .attr("id", (d, i) => `dock-$variables[i]`);

      dock.append("circle")
      .attr("cx", (d, i) => circleRadius * (2 * i + 1))
      .attr("cy", circleRadius)
      .attr("r", circleRadius)
      .style("stroke", "none")
      .style("fill", "palegoldenrod");

      dock.append("text")
      .attr("x", (d, i) => circleRadius * (2 * i + 1))
      .attr("y", circleRadius)
      .attr("text-anchor", "middle")
      .style("fill", "white")
      .text((d, i) => variables[i]);

      const draggablesGroup = svg.append('g')
      .attr('id', 'draggables');

      const draggables = draggablesGroup.selectAll('g')
      .data(variables)
      .enter().append("g")
      .attr("id", (d, i) => variables[i])
      .call(d3.drag()
      .on("start", dragStarted)
      .on("drag", dragged)
      .on("end", dragEnded));

      draggables.append('circle')
      .attr("cx", (d, i) => circleRadius * (2 * i + 1))
      .attr("cy", circleRadius)
      .attr("initial_x", (d, i) => circleRadius * (2 * i + 1))
      .attr("initial_y", circleRadius)
      .attr("r", circleRadius)
      .style("stroke", "orange")
      .style("fill", "yellowgreen");

      draggables.append("text")
      .attr("x", (d, i) => circleRadius * (2 * i + 1))
      .attr("y", circleRadius)
      .attr("text-anchor", "middle")
      .style("fill", "white")
      .text((d, i) => variables[i]);

      svg.append('rect')
      .attr("x", 960/2)
      .attr("y", 0)
      .attr("width", 100)
      .attr("height", 500/2)
      .attr("fill-opacity", 0)
      .style("stroke", "#848276")
      .attr("id", "hitZone");

      // functions
      function dragStarted()
      d3.select(this).raise().classed("active", true);


      function dragged()
      d3.select(this).select("text").attr("x", d3.event.x).attr("y", d3.event.y);
      d3.select(this).select("circle").attr("cx", d3.event.x).attr("cy", d3.event.y);


      function dragEnded()
      d3.select(this).classed("active", false);
      d3.select(this).lower();
      let hit = d3.select(document.elementFromPoint(d3.event.sourceEvent.clientX, d3.event.sourceEvent.clientY)).attr("id");

      if (hit == "hitZone")
      inZone.push(this.id);
      if (inZone.length > 1)
      let resetVar = inZone.shift();
      resetCircle(resetVar);



      d3.select(this).raise();


      function resetCircle(resetVar)
      let current_x = d3.select(`#$resetVar`)
      .select('circle')
      .attr('cx');

      let current_y = d3.select(`#$resetVar`)
      .select('circle')
      .attr('cy');

      let initial_x = d3.select(`#$resetVar`)
      .select('circle')
      .attr('initial_x');

      let initial_y = d3.select(`#$resetVar`)
      .select('circle')
      .attr('initial_y');

      d3.select(`#$resetVar`)
      .transition()
      .duration(2000)
      .style('opacity', 0)
      .transition()
      .duration(2000)
      .attr('transform', `translate($-current_x, $-current_y)`)
      .transition()
      .duration(2000)
      .style('opacity', 1);

       body margin:0;position:fixed;top:0;right:0;bottom:0;left:0; 

       <script src="https://d3js.org/d3.v5.min.js"></script>





       const circleRadius = 40;
      const variables = ['one', 'two', 'three', 'four'];
      const inZone = [];

      // DOM elements
      const svg = d3.select("body").append("svg")
      .attr("width", 960)
      .attr("height", 500)

      const dragDockGroup = svg.append('g')
      .attr('id', 'draggables-dock');

      const dock = dragDockGroup.selectAll('g')
      .data(variables)
      .enter().append("g")
      .attr("id", (d, i) => `dock-$variables[i]`);

      dock.append("circle")
      .attr("cx", (d, i) => circleRadius * (2 * i + 1))
      .attr("cy", circleRadius)
      .attr("r", circleRadius)
      .style("stroke", "none")
      .style("fill", "palegoldenrod");

      dock.append("text")
      .attr("x", (d, i) => circleRadius * (2 * i + 1))
      .attr("y", circleRadius)
      .attr("text-anchor", "middle")
      .style("fill", "white")
      .text((d, i) => variables[i]);

      const draggablesGroup = svg.append('g')
      .attr('id', 'draggables');

      const draggables = draggablesGroup.selectAll('g')
      .data(variables)
      .enter().append("g")
      .attr("id", (d, i) => variables[i])
      .call(d3.drag()
      .on("start", dragStarted)
      .on("drag", dragged)
      .on("end", dragEnded));

      draggables.append('circle')
      .attr("cx", (d, i) => circleRadius * (2 * i + 1))
      .attr("cy", circleRadius)
      .attr("initial_x", (d, i) => circleRadius * (2 * i + 1))
      .attr("initial_y", circleRadius)
      .attr("r", circleRadius)
      .style("stroke", "orange")
      .style("fill", "yellowgreen");

      draggables.append("text")
      .attr("x", (d, i) => circleRadius * (2 * i + 1))
      .attr("y", circleRadius)
      .attr("text-anchor", "middle")
      .style("fill", "white")
      .text((d, i) => variables[i]);

      svg.append('rect')
      .attr("x", 960/2)
      .attr("y", 0)
      .attr("width", 100)
      .attr("height", 500/2)
      .attr("fill-opacity", 0)
      .style("stroke", "#848276")
      .attr("id", "hitZone");

      // functions
      function dragStarted()
      d3.select(this).raise().classed("active", true);


      function dragged()
      d3.select(this).select("text").attr("x", d3.event.x).attr("y", d3.event.y);
      d3.select(this).select("circle").attr("cx", d3.event.x).attr("cy", d3.event.y);


      function dragEnded()
      d3.select(this).classed("active", false);
      d3.select(this).lower();
      let hit = d3.select(document.elementFromPoint(d3.event.sourceEvent.clientX, d3.event.sourceEvent.clientY)).attr("id");

      if (hit == "hitZone")
      inZone.push(this.id);
      if (inZone.length > 1)
      let resetVar = inZone.shift();
      resetCircle(resetVar);



      d3.select(this).raise();


      function resetCircle(resetVar)
      let current_x = d3.select(`#$resetVar`)
      .select('circle')
      .attr('cx');

      let current_y = d3.select(`#$resetVar`)
      .select('circle')
      .attr('cy');

      let initial_x = d3.select(`#$resetVar`)
      .select('circle')
      .attr('initial_x');

      let initial_y = d3.select(`#$resetVar`)
      .select('circle')
      .attr('initial_y');

      d3.select(`#$resetVar`)
      .transition()
      .duration(2000)
      .style('opacity', 0)
      .transition()
      .duration(2000)
      .attr('transform', `translate($-current_x, $-current_y)`)
      .transition()
      .duration(2000)
      .style('opacity', 1);

       body margin:0;position:fixed;top:0;right:0;bottom:0;left:0; 

       <script src="https://d3js.org/d3.v5.min.js"></script>






      javascript d3.js svg transform






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Mar 27 at 4:28









      Gerardo Furtado

      72.8k8 gold badges54 silver badges102 bronze badges




      72.8k8 gold badges54 silver badges102 bronze badges










      asked Mar 27 at 1:26









      interwebjillinterwebjill

      3752 silver badges19 bronze badges




      3752 silver badges19 bronze badges

























          1 Answer
          1






          active

          oldest

          votes


















          3














          Your code runs into difficulties because you are positioning both the g elements and the children text and circles.



          Circles and text are originally positioned by x/y attributes:



          draggables.append('circle')
          .attr("cx", (d, i) => circleRadius * (2 * i + 1))
          .attr("cy", circleRadius)

          draggables.append("text")
          .attr("x", (d, i) => circleRadius * (2 * i + 1))
          .attr("y", circleRadius)


          Drag events move the circles and text here:



          d3.select(this).select("text").attr("x", d3.event.x).attr("y", d3.event.y);
          d3.select(this).select("circle").attr("cx", d3.event.x).attr("cy", d3.event.y);


          And then we reset the circles and text by trying to offset the parent g with a transform:



          d3.select(`#$resetVar`).attr('transform', `translate($-current_x, $-current_y)`)


          Where current_x and current_y are the current x,y values for the circles and text. We have also stored the initial x,y values for the text, but altogether, this becomes a more convoluted then necessary as we have two competing sets of positioning coordinates.



          This can be simplified a fair amount. Instead of positioning both the text and the circles, simply apply a transform to the parent g holding both the circle and the text. Then when we drag we update the transform, and when we finish, we reset the transform.



          Now we have no modification of x,y/cx,cy attributes and transforms for positioning the elements relative to one another. No offsets and the parent g's transform will always represent the position of the circle and the text.



          Below I keep track of the original transform with the datum (not an element attribute) - normally I would use a property of the datum, but you have non-object data, so I just replace the datum with the original transform:






          const circleRadius = 40;
          const variables = ['one', 'two', 'three', 'four'];
          const inZone = [];

          // DOM elements
          const svg = d3.select("body").append("svg")
          .attr("width", 960)
          .attr("height", 500)

          const dragDockGroup = svg.append('g')
          .attr('id', 'draggables-dock');

          // Immovable placemarkers:
          const dock = dragDockGroup.selectAll('g')
          .data(variables)
          .enter().append("g")
          .attr("id", (d, i) => `dock-$variables[i]`);

          dock.append("circle")
          .attr("cx", (d, i) => circleRadius * (2 * i + 1))
          .attr("cy", circleRadius)
          .attr("r", circleRadius)
          .style("stroke", "none")
          .style("fill", "palegoldenrod");

          dock.append("text")
          .attr("x", (d, i) => circleRadius * (2 * i + 1))
          .attr("y", circleRadius)
          .attr("text-anchor", "middle")
          .style("fill", "white")
          .text((d, i) => variables[i]);

          // Dragables
          const draggablesGroup = svg.append('g')
          .attr('id', 'draggables');

          const draggables = draggablesGroup.selectAll('g')
          .data(variables)
          .enter()
          .append("g")
          .datum(function(d,i)
          return "translate("+[circleRadius * (2 * i + 1),circleRadius]+")";
          )
          .attr("transform", (d,i) => d)
          .attr("id", (d, i) => variables[i])
          .call(d3.drag()
          .on("start", dragStarted)
          .on("drag", dragged)
          .on("end", dragEnded));

          draggables.append('circle')
          .attr("r", circleRadius)
          .style("stroke", "orange")
          .style("fill", "yellowgreen");

          draggables.append("text")
          .attr("text-anchor", "middle")
          .style("fill", "white")
          .text((d, i) => variables[i]);

          svg.append('rect')
          .attr("x", 960/2)
          .attr("y", 0)
          .attr("width", 100)
          .attr("height", 500/2)
          .attr("fill-opacity", 0)
          .style("stroke", "#848276")
          .attr("id", "hitZone");

          // functions
          function dragStarted()
          d3.select(this).raise();


          function dragged()
          d3.select(this).attr("transform","translate("+[d3.event.x,d3.event.y]+")")


          function dragEnded()
          d3.select(this).lower();
          let hit = d3.select(document.elementFromPoint(d3.event.sourceEvent.clientX, d3.event.sourceEvent.clientY)).attr("id");

          if (hit == "hitZone")
          inZone.push(this.id);
          if (inZone.length > 1)
          let resetVar = inZone.shift();
          resetCircle(resetVar);



          d3.select(this).raise();


          function resetCircle(resetVar)
          d3.select(`#$resetVar`)
          .transition()
          .duration(500)
          .style('opacity', 0)
          .transition()
          .duration(500)
          .attr("transform", (d,i) => d)
          .transition()
          .duration(500)
          .style('opacity', 1);


          body margin:0;position:fixed;top:0;right:0;bottom:0;left:0; 

          <script src="https://d3js.org/d3.v5.min.js"></script>








          share|improve this answer
























            Your Answer






            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "1"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader:
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            ,
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );













            draft saved

            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55368471%2fresetting-drag-with-multiple-elements%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            3














            Your code runs into difficulties because you are positioning both the g elements and the children text and circles.



            Circles and text are originally positioned by x/y attributes:



            draggables.append('circle')
            .attr("cx", (d, i) => circleRadius * (2 * i + 1))
            .attr("cy", circleRadius)

            draggables.append("text")
            .attr("x", (d, i) => circleRadius * (2 * i + 1))
            .attr("y", circleRadius)


            Drag events move the circles and text here:



            d3.select(this).select("text").attr("x", d3.event.x).attr("y", d3.event.y);
            d3.select(this).select("circle").attr("cx", d3.event.x).attr("cy", d3.event.y);


            And then we reset the circles and text by trying to offset the parent g with a transform:



            d3.select(`#$resetVar`).attr('transform', `translate($-current_x, $-current_y)`)


            Where current_x and current_y are the current x,y values for the circles and text. We have also stored the initial x,y values for the text, but altogether, this becomes a more convoluted then necessary as we have two competing sets of positioning coordinates.



            This can be simplified a fair amount. Instead of positioning both the text and the circles, simply apply a transform to the parent g holding both the circle and the text. Then when we drag we update the transform, and when we finish, we reset the transform.



            Now we have no modification of x,y/cx,cy attributes and transforms for positioning the elements relative to one another. No offsets and the parent g's transform will always represent the position of the circle and the text.



            Below I keep track of the original transform with the datum (not an element attribute) - normally I would use a property of the datum, but you have non-object data, so I just replace the datum with the original transform:






            const circleRadius = 40;
            const variables = ['one', 'two', 'three', 'four'];
            const inZone = [];

            // DOM elements
            const svg = d3.select("body").append("svg")
            .attr("width", 960)
            .attr("height", 500)

            const dragDockGroup = svg.append('g')
            .attr('id', 'draggables-dock');

            // Immovable placemarkers:
            const dock = dragDockGroup.selectAll('g')
            .data(variables)
            .enter().append("g")
            .attr("id", (d, i) => `dock-$variables[i]`);

            dock.append("circle")
            .attr("cx", (d, i) => circleRadius * (2 * i + 1))
            .attr("cy", circleRadius)
            .attr("r", circleRadius)
            .style("stroke", "none")
            .style("fill", "palegoldenrod");

            dock.append("text")
            .attr("x", (d, i) => circleRadius * (2 * i + 1))
            .attr("y", circleRadius)
            .attr("text-anchor", "middle")
            .style("fill", "white")
            .text((d, i) => variables[i]);

            // Dragables
            const draggablesGroup = svg.append('g')
            .attr('id', 'draggables');

            const draggables = draggablesGroup.selectAll('g')
            .data(variables)
            .enter()
            .append("g")
            .datum(function(d,i)
            return "translate("+[circleRadius * (2 * i + 1),circleRadius]+")";
            )
            .attr("transform", (d,i) => d)
            .attr("id", (d, i) => variables[i])
            .call(d3.drag()
            .on("start", dragStarted)
            .on("drag", dragged)
            .on("end", dragEnded));

            draggables.append('circle')
            .attr("r", circleRadius)
            .style("stroke", "orange")
            .style("fill", "yellowgreen");

            draggables.append("text")
            .attr("text-anchor", "middle")
            .style("fill", "white")
            .text((d, i) => variables[i]);

            svg.append('rect')
            .attr("x", 960/2)
            .attr("y", 0)
            .attr("width", 100)
            .attr("height", 500/2)
            .attr("fill-opacity", 0)
            .style("stroke", "#848276")
            .attr("id", "hitZone");

            // functions
            function dragStarted()
            d3.select(this).raise();


            function dragged()
            d3.select(this).attr("transform","translate("+[d3.event.x,d3.event.y]+")")


            function dragEnded()
            d3.select(this).lower();
            let hit = d3.select(document.elementFromPoint(d3.event.sourceEvent.clientX, d3.event.sourceEvent.clientY)).attr("id");

            if (hit == "hitZone")
            inZone.push(this.id);
            if (inZone.length > 1)
            let resetVar = inZone.shift();
            resetCircle(resetVar);



            d3.select(this).raise();


            function resetCircle(resetVar)
            d3.select(`#$resetVar`)
            .transition()
            .duration(500)
            .style('opacity', 0)
            .transition()
            .duration(500)
            .attr("transform", (d,i) => d)
            .transition()
            .duration(500)
            .style('opacity', 1);


            body margin:0;position:fixed;top:0;right:0;bottom:0;left:0; 

            <script src="https://d3js.org/d3.v5.min.js"></script>








            share|improve this answer





























              3














              Your code runs into difficulties because you are positioning both the g elements and the children text and circles.



              Circles and text are originally positioned by x/y attributes:



              draggables.append('circle')
              .attr("cx", (d, i) => circleRadius * (2 * i + 1))
              .attr("cy", circleRadius)

              draggables.append("text")
              .attr("x", (d, i) => circleRadius * (2 * i + 1))
              .attr("y", circleRadius)


              Drag events move the circles and text here:



              d3.select(this).select("text").attr("x", d3.event.x).attr("y", d3.event.y);
              d3.select(this).select("circle").attr("cx", d3.event.x).attr("cy", d3.event.y);


              And then we reset the circles and text by trying to offset the parent g with a transform:



              d3.select(`#$resetVar`).attr('transform', `translate($-current_x, $-current_y)`)


              Where current_x and current_y are the current x,y values for the circles and text. We have also stored the initial x,y values for the text, but altogether, this becomes a more convoluted then necessary as we have two competing sets of positioning coordinates.



              This can be simplified a fair amount. Instead of positioning both the text and the circles, simply apply a transform to the parent g holding both the circle and the text. Then when we drag we update the transform, and when we finish, we reset the transform.



              Now we have no modification of x,y/cx,cy attributes and transforms for positioning the elements relative to one another. No offsets and the parent g's transform will always represent the position of the circle and the text.



              Below I keep track of the original transform with the datum (not an element attribute) - normally I would use a property of the datum, but you have non-object data, so I just replace the datum with the original transform:






              const circleRadius = 40;
              const variables = ['one', 'two', 'three', 'four'];
              const inZone = [];

              // DOM elements
              const svg = d3.select("body").append("svg")
              .attr("width", 960)
              .attr("height", 500)

              const dragDockGroup = svg.append('g')
              .attr('id', 'draggables-dock');

              // Immovable placemarkers:
              const dock = dragDockGroup.selectAll('g')
              .data(variables)
              .enter().append("g")
              .attr("id", (d, i) => `dock-$variables[i]`);

              dock.append("circle")
              .attr("cx", (d, i) => circleRadius * (2 * i + 1))
              .attr("cy", circleRadius)
              .attr("r", circleRadius)
              .style("stroke", "none")
              .style("fill", "palegoldenrod");

              dock.append("text")
              .attr("x", (d, i) => circleRadius * (2 * i + 1))
              .attr("y", circleRadius)
              .attr("text-anchor", "middle")
              .style("fill", "white")
              .text((d, i) => variables[i]);

              // Dragables
              const draggablesGroup = svg.append('g')
              .attr('id', 'draggables');

              const draggables = draggablesGroup.selectAll('g')
              .data(variables)
              .enter()
              .append("g")
              .datum(function(d,i)
              return "translate("+[circleRadius * (2 * i + 1),circleRadius]+")";
              )
              .attr("transform", (d,i) => d)
              .attr("id", (d, i) => variables[i])
              .call(d3.drag()
              .on("start", dragStarted)
              .on("drag", dragged)
              .on("end", dragEnded));

              draggables.append('circle')
              .attr("r", circleRadius)
              .style("stroke", "orange")
              .style("fill", "yellowgreen");

              draggables.append("text")
              .attr("text-anchor", "middle")
              .style("fill", "white")
              .text((d, i) => variables[i]);

              svg.append('rect')
              .attr("x", 960/2)
              .attr("y", 0)
              .attr("width", 100)
              .attr("height", 500/2)
              .attr("fill-opacity", 0)
              .style("stroke", "#848276")
              .attr("id", "hitZone");

              // functions
              function dragStarted()
              d3.select(this).raise();


              function dragged()
              d3.select(this).attr("transform","translate("+[d3.event.x,d3.event.y]+")")


              function dragEnded()
              d3.select(this).lower();
              let hit = d3.select(document.elementFromPoint(d3.event.sourceEvent.clientX, d3.event.sourceEvent.clientY)).attr("id");

              if (hit == "hitZone")
              inZone.push(this.id);
              if (inZone.length > 1)
              let resetVar = inZone.shift();
              resetCircle(resetVar);



              d3.select(this).raise();


              function resetCircle(resetVar)
              d3.select(`#$resetVar`)
              .transition()
              .duration(500)
              .style('opacity', 0)
              .transition()
              .duration(500)
              .attr("transform", (d,i) => d)
              .transition()
              .duration(500)
              .style('opacity', 1);


              body margin:0;position:fixed;top:0;right:0;bottom:0;left:0; 

              <script src="https://d3js.org/d3.v5.min.js"></script>








              share|improve this answer



























                3












                3








                3







                Your code runs into difficulties because you are positioning both the g elements and the children text and circles.



                Circles and text are originally positioned by x/y attributes:



                draggables.append('circle')
                .attr("cx", (d, i) => circleRadius * (2 * i + 1))
                .attr("cy", circleRadius)

                draggables.append("text")
                .attr("x", (d, i) => circleRadius * (2 * i + 1))
                .attr("y", circleRadius)


                Drag events move the circles and text here:



                d3.select(this).select("text").attr("x", d3.event.x).attr("y", d3.event.y);
                d3.select(this).select("circle").attr("cx", d3.event.x).attr("cy", d3.event.y);


                And then we reset the circles and text by trying to offset the parent g with a transform:



                d3.select(`#$resetVar`).attr('transform', `translate($-current_x, $-current_y)`)


                Where current_x and current_y are the current x,y values for the circles and text. We have also stored the initial x,y values for the text, but altogether, this becomes a more convoluted then necessary as we have two competing sets of positioning coordinates.



                This can be simplified a fair amount. Instead of positioning both the text and the circles, simply apply a transform to the parent g holding both the circle and the text. Then when we drag we update the transform, and when we finish, we reset the transform.



                Now we have no modification of x,y/cx,cy attributes and transforms for positioning the elements relative to one another. No offsets and the parent g's transform will always represent the position of the circle and the text.



                Below I keep track of the original transform with the datum (not an element attribute) - normally I would use a property of the datum, but you have non-object data, so I just replace the datum with the original transform:






                const circleRadius = 40;
                const variables = ['one', 'two', 'three', 'four'];
                const inZone = [];

                // DOM elements
                const svg = d3.select("body").append("svg")
                .attr("width", 960)
                .attr("height", 500)

                const dragDockGroup = svg.append('g')
                .attr('id', 'draggables-dock');

                // Immovable placemarkers:
                const dock = dragDockGroup.selectAll('g')
                .data(variables)
                .enter().append("g")
                .attr("id", (d, i) => `dock-$variables[i]`);

                dock.append("circle")
                .attr("cx", (d, i) => circleRadius * (2 * i + 1))
                .attr("cy", circleRadius)
                .attr("r", circleRadius)
                .style("stroke", "none")
                .style("fill", "palegoldenrod");

                dock.append("text")
                .attr("x", (d, i) => circleRadius * (2 * i + 1))
                .attr("y", circleRadius)
                .attr("text-anchor", "middle")
                .style("fill", "white")
                .text((d, i) => variables[i]);

                // Dragables
                const draggablesGroup = svg.append('g')
                .attr('id', 'draggables');

                const draggables = draggablesGroup.selectAll('g')
                .data(variables)
                .enter()
                .append("g")
                .datum(function(d,i)
                return "translate("+[circleRadius * (2 * i + 1),circleRadius]+")";
                )
                .attr("transform", (d,i) => d)
                .attr("id", (d, i) => variables[i])
                .call(d3.drag()
                .on("start", dragStarted)
                .on("drag", dragged)
                .on("end", dragEnded));

                draggables.append('circle')
                .attr("r", circleRadius)
                .style("stroke", "orange")
                .style("fill", "yellowgreen");

                draggables.append("text")
                .attr("text-anchor", "middle")
                .style("fill", "white")
                .text((d, i) => variables[i]);

                svg.append('rect')
                .attr("x", 960/2)
                .attr("y", 0)
                .attr("width", 100)
                .attr("height", 500/2)
                .attr("fill-opacity", 0)
                .style("stroke", "#848276")
                .attr("id", "hitZone");

                // functions
                function dragStarted()
                d3.select(this).raise();


                function dragged()
                d3.select(this).attr("transform","translate("+[d3.event.x,d3.event.y]+")")


                function dragEnded()
                d3.select(this).lower();
                let hit = d3.select(document.elementFromPoint(d3.event.sourceEvent.clientX, d3.event.sourceEvent.clientY)).attr("id");

                if (hit == "hitZone")
                inZone.push(this.id);
                if (inZone.length > 1)
                let resetVar = inZone.shift();
                resetCircle(resetVar);



                d3.select(this).raise();


                function resetCircle(resetVar)
                d3.select(`#$resetVar`)
                .transition()
                .duration(500)
                .style('opacity', 0)
                .transition()
                .duration(500)
                .attr("transform", (d,i) => d)
                .transition()
                .duration(500)
                .style('opacity', 1);


                body margin:0;position:fixed;top:0;right:0;bottom:0;left:0; 

                <script src="https://d3js.org/d3.v5.min.js"></script>








                share|improve this answer













                Your code runs into difficulties because you are positioning both the g elements and the children text and circles.



                Circles and text are originally positioned by x/y attributes:



                draggables.append('circle')
                .attr("cx", (d, i) => circleRadius * (2 * i + 1))
                .attr("cy", circleRadius)

                draggables.append("text")
                .attr("x", (d, i) => circleRadius * (2 * i + 1))
                .attr("y", circleRadius)


                Drag events move the circles and text here:



                d3.select(this).select("text").attr("x", d3.event.x).attr("y", d3.event.y);
                d3.select(this).select("circle").attr("cx", d3.event.x).attr("cy", d3.event.y);


                And then we reset the circles and text by trying to offset the parent g with a transform:



                d3.select(`#$resetVar`).attr('transform', `translate($-current_x, $-current_y)`)


                Where current_x and current_y are the current x,y values for the circles and text. We have also stored the initial x,y values for the text, but altogether, this becomes a more convoluted then necessary as we have two competing sets of positioning coordinates.



                This can be simplified a fair amount. Instead of positioning both the text and the circles, simply apply a transform to the parent g holding both the circle and the text. Then when we drag we update the transform, and when we finish, we reset the transform.



                Now we have no modification of x,y/cx,cy attributes and transforms for positioning the elements relative to one another. No offsets and the parent g's transform will always represent the position of the circle and the text.



                Below I keep track of the original transform with the datum (not an element attribute) - normally I would use a property of the datum, but you have non-object data, so I just replace the datum with the original transform:






                const circleRadius = 40;
                const variables = ['one', 'two', 'three', 'four'];
                const inZone = [];

                // DOM elements
                const svg = d3.select("body").append("svg")
                .attr("width", 960)
                .attr("height", 500)

                const dragDockGroup = svg.append('g')
                .attr('id', 'draggables-dock');

                // Immovable placemarkers:
                const dock = dragDockGroup.selectAll('g')
                .data(variables)
                .enter().append("g")
                .attr("id", (d, i) => `dock-$variables[i]`);

                dock.append("circle")
                .attr("cx", (d, i) => circleRadius * (2 * i + 1))
                .attr("cy", circleRadius)
                .attr("r", circleRadius)
                .style("stroke", "none")
                .style("fill", "palegoldenrod");

                dock.append("text")
                .attr("x", (d, i) => circleRadius * (2 * i + 1))
                .attr("y", circleRadius)
                .attr("text-anchor", "middle")
                .style("fill", "white")
                .text((d, i) => variables[i]);

                // Dragables
                const draggablesGroup = svg.append('g')
                .attr('id', 'draggables');

                const draggables = draggablesGroup.selectAll('g')
                .data(variables)
                .enter()
                .append("g")
                .datum(function(d,i)
                return "translate("+[circleRadius * (2 * i + 1),circleRadius]+")";
                )
                .attr("transform", (d,i) => d)
                .attr("id", (d, i) => variables[i])
                .call(d3.drag()
                .on("start", dragStarted)
                .on("drag", dragged)
                .on("end", dragEnded));

                draggables.append('circle')
                .attr("r", circleRadius)
                .style("stroke", "orange")
                .style("fill", "yellowgreen");

                draggables.append("text")
                .attr("text-anchor", "middle")
                .style("fill", "white")
                .text((d, i) => variables[i]);

                svg.append('rect')
                .attr("x", 960/2)
                .attr("y", 0)
                .attr("width", 100)
                .attr("height", 500/2)
                .attr("fill-opacity", 0)
                .style("stroke", "#848276")
                .attr("id", "hitZone");

                // functions
                function dragStarted()
                d3.select(this).raise();


                function dragged()
                d3.select(this).attr("transform","translate("+[d3.event.x,d3.event.y]+")")


                function dragEnded()
                d3.select(this).lower();
                let hit = d3.select(document.elementFromPoint(d3.event.sourceEvent.clientX, d3.event.sourceEvent.clientY)).attr("id");

                if (hit == "hitZone")
                inZone.push(this.id);
                if (inZone.length > 1)
                let resetVar = inZone.shift();
                resetCircle(resetVar);



                d3.select(this).raise();


                function resetCircle(resetVar)
                d3.select(`#$resetVar`)
                .transition()
                .duration(500)
                .style('opacity', 0)
                .transition()
                .duration(500)
                .attr("transform", (d,i) => d)
                .transition()
                .duration(500)
                .style('opacity', 1);


                body margin:0;position:fixed;top:0;right:0;bottom:0;left:0; 

                <script src="https://d3js.org/d3.v5.min.js"></script>








                const circleRadius = 40;
                const variables = ['one', 'two', 'three', 'four'];
                const inZone = [];

                // DOM elements
                const svg = d3.select("body").append("svg")
                .attr("width", 960)
                .attr("height", 500)

                const dragDockGroup = svg.append('g')
                .attr('id', 'draggables-dock');

                // Immovable placemarkers:
                const dock = dragDockGroup.selectAll('g')
                .data(variables)
                .enter().append("g")
                .attr("id", (d, i) => `dock-$variables[i]`);

                dock.append("circle")
                .attr("cx", (d, i) => circleRadius * (2 * i + 1))
                .attr("cy", circleRadius)
                .attr("r", circleRadius)
                .style("stroke", "none")
                .style("fill", "palegoldenrod");

                dock.append("text")
                .attr("x", (d, i) => circleRadius * (2 * i + 1))
                .attr("y", circleRadius)
                .attr("text-anchor", "middle")
                .style("fill", "white")
                .text((d, i) => variables[i]);

                // Dragables
                const draggablesGroup = svg.append('g')
                .attr('id', 'draggables');

                const draggables = draggablesGroup.selectAll('g')
                .data(variables)
                .enter()
                .append("g")
                .datum(function(d,i)
                return "translate("+[circleRadius * (2 * i + 1),circleRadius]+")";
                )
                .attr("transform", (d,i) => d)
                .attr("id", (d, i) => variables[i])
                .call(d3.drag()
                .on("start", dragStarted)
                .on("drag", dragged)
                .on("end", dragEnded));

                draggables.append('circle')
                .attr("r", circleRadius)
                .style("stroke", "orange")
                .style("fill", "yellowgreen");

                draggables.append("text")
                .attr("text-anchor", "middle")
                .style("fill", "white")
                .text((d, i) => variables[i]);

                svg.append('rect')
                .attr("x", 960/2)
                .attr("y", 0)
                .attr("width", 100)
                .attr("height", 500/2)
                .attr("fill-opacity", 0)
                .style("stroke", "#848276")
                .attr("id", "hitZone");

                // functions
                function dragStarted()
                d3.select(this).raise();


                function dragged()
                d3.select(this).attr("transform","translate("+[d3.event.x,d3.event.y]+")")


                function dragEnded()
                d3.select(this).lower();
                let hit = d3.select(document.elementFromPoint(d3.event.sourceEvent.clientX, d3.event.sourceEvent.clientY)).attr("id");

                if (hit == "hitZone")
                inZone.push(this.id);
                if (inZone.length > 1)
                let resetVar = inZone.shift();
                resetCircle(resetVar);



                d3.select(this).raise();


                function resetCircle(resetVar)
                d3.select(`#$resetVar`)
                .transition()
                .duration(500)
                .style('opacity', 0)
                .transition()
                .duration(500)
                .attr("transform", (d,i) => d)
                .transition()
                .duration(500)
                .style('opacity', 1);


                body margin:0;position:fixed;top:0;right:0;bottom:0;left:0; 

                <script src="https://d3js.org/d3.v5.min.js"></script>





                const circleRadius = 40;
                const variables = ['one', 'two', 'three', 'four'];
                const inZone = [];

                // DOM elements
                const svg = d3.select("body").append("svg")
                .attr("width", 960)
                .attr("height", 500)

                const dragDockGroup = svg.append('g')
                .attr('id', 'draggables-dock');

                // Immovable placemarkers:
                const dock = dragDockGroup.selectAll('g')
                .data(variables)
                .enter().append("g")
                .attr("id", (d, i) => `dock-$variables[i]`);

                dock.append("circle")
                .attr("cx", (d, i) => circleRadius * (2 * i + 1))
                .attr("cy", circleRadius)
                .attr("r", circleRadius)
                .style("stroke", "none")
                .style("fill", "palegoldenrod");

                dock.append("text")
                .attr("x", (d, i) => circleRadius * (2 * i + 1))
                .attr("y", circleRadius)
                .attr("text-anchor", "middle")
                .style("fill", "white")
                .text((d, i) => variables[i]);

                // Dragables
                const draggablesGroup = svg.append('g')
                .attr('id', 'draggables');

                const draggables = draggablesGroup.selectAll('g')
                .data(variables)
                .enter()
                .append("g")
                .datum(function(d,i)
                return "translate("+[circleRadius * (2 * i + 1),circleRadius]+")";
                )
                .attr("transform", (d,i) => d)
                .attr("id", (d, i) => variables[i])
                .call(d3.drag()
                .on("start", dragStarted)
                .on("drag", dragged)
                .on("end", dragEnded));

                draggables.append('circle')
                .attr("r", circleRadius)
                .style("stroke", "orange")
                .style("fill", "yellowgreen");

                draggables.append("text")
                .attr("text-anchor", "middle")
                .style("fill", "white")
                .text((d, i) => variables[i]);

                svg.append('rect')
                .attr("x", 960/2)
                .attr("y", 0)
                .attr("width", 100)
                .attr("height", 500/2)
                .attr("fill-opacity", 0)
                .style("stroke", "#848276")
                .attr("id", "hitZone");

                // functions
                function dragStarted()
                d3.select(this).raise();


                function dragged()
                d3.select(this).attr("transform","translate("+[d3.event.x,d3.event.y]+")")


                function dragEnded()
                d3.select(this).lower();
                let hit = d3.select(document.elementFromPoint(d3.event.sourceEvent.clientX, d3.event.sourceEvent.clientY)).attr("id");

                if (hit == "hitZone")
                inZone.push(this.id);
                if (inZone.length > 1)
                let resetVar = inZone.shift();
                resetCircle(resetVar);



                d3.select(this).raise();


                function resetCircle(resetVar)
                d3.select(`#$resetVar`)
                .transition()
                .duration(500)
                .style('opacity', 0)
                .transition()
                .duration(500)
                .attr("transform", (d,i) => d)
                .transition()
                .duration(500)
                .style('opacity', 1);


                body margin:0;position:fixed;top:0;right:0;bottom:0;left:0; 

                <script src="https://d3js.org/d3.v5.min.js"></script>






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Mar 27 at 4:26









                Andrew ReidAndrew Reid

                21.4k5 gold badges29 silver badges50 bronze badges




                21.4k5 gold badges29 silver badges50 bronze badges





















                    Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.







                    Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.



















                    draft saved

                    draft discarded
















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid


                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.

                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55368471%2fresetting-drag-with-multiple-elements%23new-answer', 'question_page');

                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    SQL error code 1064 with creating Laravel foreign keysForeign key constraints: When to use ON UPDATE and ON DELETEDropping column with foreign key Laravel error: General error: 1025 Error on renameLaravel SQL Can't create tableLaravel Migration foreign key errorLaravel php artisan migrate:refresh giving a syntax errorSQLSTATE[42S01]: Base table or view already exists or Base table or view already exists: 1050 Tableerror in migrating laravel file to xampp serverSyntax error or access violation: 1064:syntax to use near 'unsigned not null, modelName varchar(191) not null, title varchar(191) not nLaravel cannot create new table field in mysqlLaravel 5.7:Last migration creates table but is not registered in the migration table

                    용인 삼성생명 블루밍스 목차 통계 역대 감독 선수단 응원단 경기장 같이 보기 외부 링크 둘러보기 메뉴samsungblueminx.comeh선수 명단용인 삼성생명 블루밍스용인 삼성생명 블루밍스ehsamsungblueminx.comeheheheh

                    155 수학 과학 기타 둘러보기 메뉴eh추가해eh문서를 완성해