block by micahstubbs 5135994b936e7294911fa28520f015c1

Multiple Shape Drag Canvas

Full Screen

a Canvas example that shows how to drag multiple shapes inside of another shape. notice that the red circles can be dragged independently. notice that the black rectangle can also be dragged, keeping it’s red-circle children in the same relative positions.

you could also think about this problem as “how to create a hierarchy of draggable shapes?”. the short answer is: do it in the dragSubject() function d3-drag docs on drag subjects

a fork of Multiple Shape Drag SVG

an iteration on this very helpful stackoverflow answer

this collection of d3-drag experiments also exist in github repo form at micahstubbs/d3-drag-experiments

index.html

<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.2/d3.min.js"></script>
    <meta charset="utf-8">
    <title>d3-drag-experiments</title>
  </head>
  <body>
    <script src="vis.js"></script>
  </body>
</html>

preview.xcf

gimp xcf file��B�B�gimp-image-grid(style solid)
(fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000))
(bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000))
(xspacing 10.000000)
(yspacing 10.000000)
(spacing-unit inches)
(xoffset 0.000000)
(yoffset 0.000000)
(offset-unit inches)
���)Screen Shot 2017-09-10 at 9.34.36 PM.png�	

\���!�!�!�!������	v	�	�	�	�	�	�	�	�


&
6
z���(8HXhx��������� 0@P`p���<Xt
*:JZjz��������
*:JZjz��������
*:JZjz�������� 
  * : J Z j z � � � � � � � �!
!!*!:!J!Z!j!z!�!�!�!���1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1��1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1��1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1���@��@��@���@��@��@���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
�1
�,�h���
�+�e���*����)����(�e��'����'�h��'����'����'�'�'����'����'�h��'����(�e��)����*����+�e���,�h���
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1�?���h9���e8���7���6��e5���4��h4���4���4	�5	�5���4���4��h4���4��e5���6���7���e8���hf�h�����h3�e�����e1���
���/������-�e���e+������*�h���h*������*������*�+�+������*������*�h���h*������+�e���e-������/���
���1�e�����e3�h�����h��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1��
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1��
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1
�1���@��@��@���@��@��@��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
������������}x><

vis.js

/* prettier-ignore */
d3.select('body')
  .append('canvas')
  .attr('width', 960)
  .attr('height', 500);

const canvas = d3.select('canvas');
const context = canvas.node().getContext('2d');
const width = canvas.property('width');
const height = canvas.property('height');

const circles = [{ x: 50, y: 60, radius: 10 }, { x: 100, y: 80, radius: 10 }];
const rects = [{ x: 10, y: 10, x2: 210, y2: 210 }];

render();

canvas.call(
  d3
    .drag()
    .subject(dragSubject)
    .on('start', dragStarted)
    .on('drag', dragged)
    .on('end', dragEnded)
    .on('start.render drag.render end.render', render)
);

function render() {
  context.clearRect(0, 0, width, height);
  // draw the black rectangle
  rects.forEach(rect => {
    context.fillStyle = 'black';
    context.clearRect(0, 0, width, height);
    context.fillRect(rect.x, rect.y, rect.x2, rect.y2);

    // draw the red circles
    circles.forEach(circle => {
      context.beginPath();
      context.moveTo(circle.x + rect.x + circle.radius, circle.y + rect.y);
      context.arc(
        circle.x + rect.x,
        circle.y + rect.y,
        circle.radius,
        0,
        2 * Math.PI
      );
      context.fillStyle = 'red';
      context.fill();
    });
  });
}

function dragSubject() {
  let i;
  const n = circles.length;
  let dx;
  let dy;
  let d2;
  const radius = 10;
  let s2 = radius * radius * 4; // Double the radius
  let circle;
  let subject;

  for (i = 0; i < n; i += 1) {
    circle = circles[i];
    console.log('circle from dragSubject', circle);
    dx = d3.event.x - circle.x - rects[0].x;
    dy = d3.event.y - circle.y - rects[0].y;
    d2 = dx * dx + dy * dy;

    console.log('dx', dx);
    console.log('dy', dy);
    console.log('d2', d2);
    console.log('s2', s2);

    if (d2 < s2) {
      subject = circle;
      s2 = d2;
    } else if (typeof subject === 'undefined') {
      rect = rects[0];
      subject = rect;
    }
  }
  return subject;
}

function dragStarted() {
  // circles.splice(circles.indexOf(d3.event.subject), 1);
  // circles.push(d3.event.subject);
  d3.event.subject.active = true;
}

function dragged() {
  d3.event.subject.x = d3.event.x;
  d3.event.subject.y = d3.event.y;
}

function dragEnded() {
  d3.event.subject.active = false;
}

// const group = container.append('g');

// const rect = group
//   .append('rect')
//   .attr('width', w)
//   .attr('height', h)
//   .attr('x', 10)
//   .attr('yx', 10);

// const circle1 = group
//   .append('circle')
//   .attr('cx', 50)
//   .attr('cy', 50)
//   .attr('r', 10)
//   .style('fill', 'red');

// const circle2 = group
//   .append('circle')
//   .attr('cx', 100)
//   .attr('cy', 70)
//   .attr('r', 10)
//   .style('fill', 'red');

// circle1.call(drag);
// circle2.call(drag);
// group.call(drag);