block by micahstubbs 6b3eb08318df8d58d5c21dcccf3063f4

Background Drag + Node Drag Force Simulation

Full Screen

a Canvas example that shows how to drag multiple shapes inside of another shape. notice that the red network-node circles can be dragged. notice that the white background of the plot can also be dragged, while keeping the red-circle children of the invisible background 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 Canvas with Force Simulation

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.38.02 PM.png�	

\���....*����������,<L\l|��������,<L\l|��������
�
�
�
�$4DTdt��5E����� 0@P`p�� �#�#�#�#�#�$$$,$<$L$\$l$|$�(@(P+�+�+�+�+�+�+�,,,&,6,F,V,f,v,�,�,�,�,�,�,�,�---&-6-F-V-f-v-�-�-�-�-�-�-�-���������������������������������������������������������������������������������������������������������������������������������������������������������������������\�����<�����<����=�����<�����<�����<�����<�����=�����<�����<�����<�����<�����=�����<�����<�����<����<������<�����<�����<�����<����=�����<�����<�����<�����<����=�����<�����<�����<����������xCDz��4���)�0��1���
���/������-������+���'�1��*������*������*��J�R�*���*�+��=�E�*��r�z�*������*������+������-������/���
���1���1�7��4��ӓQB~��;�����<����=�����<�����<�����<�����<�����=�����<�����<�����<�����<�����=�����<�����<�����<����<������<�����<�����<�����<����=�����<�����<�����<�����<����=�����<�����<�����<����������xCDz��4���)�0��1���
���/������-������+���&�1��*������*������*��J�R�*�+�+��=�E�*��q�z�*������*������+������-������/���
���1���1�7��4��ӓQB~��;�����<����=�����<�����<�����<�����<�����=�����<�����<�����<�����<�����=�����<�����<�����<����<������<�����<�����<�����<����=�����<�����<�����<�����<����=�����<�����<�����<���������������������������������������������������������������������=�����<����=�����<����=�����<�����=�����<�����=�����<�����<������<�����<���������ʗ���7���'�!��2���?�5��/������-���
���,��h�W�+������*������*��{�l�*��8�)�*�+��/��*��e�T�*������*������+������-��E�2�.���
���/���r�d��2������6��޺��������<����=�����<����=�����<�����=�����<�����=�����<�����<������<�����<���������ʗ���7���&�!��2���?�5��/������-���
���,��h�W�+������*������*��{�l�*��8�)�*�+��.��*��e�S�*������*������+������-��E�2�.������/���q�d��2������6��޺��������<����=�����<����=�����<�����=�����<�����=�����<�����<������<�����<�����������!�����=�����<�����<�����<�����<�����=�����<�����<�����<����<�����=�����<�����<�����<����<������<�����<�����<�����<����=�����<�����<�����<�����<�����=�����<�����<��=�����<�����=�����<�����<�����<����<�����=�����<�����<�����<����<������<�����<�����<�����<����=�����<�����<�����<�����<����=�����<�����<�����<�����<�����=�����<�����<�����<�����<�����O�!�����=�����<�����<�����<�����<�����=�����<�����<�����<����<�����=�����<�����<�����<����<������<�����<�����<�����<����=�����<�����<�����<�����<�����=�����<�����<��=�����<�����=�����<�����<�����<����<�����=�����<�����<�����<����<������<�����<�����<�����<����=�����<�����<�����<�����<����=�����<�����<�����<�����<�����=�����<�����<�����<��������8���C�X��3����M��0��^���.���
���,����1��*���'����!�����=�����<�����<�����<�����<�����=�����<�����<�����<����<�����=�����<�����<�����<����<������<�����<�����<�����<����=�����<�����<�����<�����<�����=�����<�����<��=�����<�����=�����<�����<�����<����<�����=�����<�����<�����<����<������<�����<�����<�����<����=�����<�����<�����<�����<����=�����<�����<�����<�����<�����=�����<�����<�����<��������8���C�X��3����M��0��^���.���
���,����1��*���&�������������ˊU0g���3���V����0���
�'��.������,����d�,��\���*����E�*���+������)��d���)��i���)������)�����*����P�+��m���+���
���-����2��.���	�^��0���w���4���n(>���
l����ˉU0g���3���V����0���
�&��.���
���,����d�,��\���*����E�*���+������)��d���)��i���)������)�����*����P�+��m���+���
���-����2��.���	�^��0���w���4���n(>���
l��������������������������������������������������<�����<������<�����<����=����=�����<�����<������<�����<����=����=�����<�����<������<�����<����=����=�����������=����=����=�����<����=�����<����=�����<�����=�����<�����=�����<�����<������<�����<������<�����<������<�����<�����<�����<����=�����<����=�����<����=�����<�����=�����<�����=�����<�����<������<�����<������<�����<������<�����<�����<�����<����=�����<����=�����<����=�����<����=�����<�����=�����<�����=�����<�����<������<�����#����������!��Ǭ������ ��̪���������Ԫ���������ܪ���������������������������=����=����=�����<����=�����<����=�����<�����=�����<�����=�����<�����<������<�����<������<�����<������<�����<�����<�����<����=�����<����=�����<����=�����<�����=�����<�����=�����<�����<������<�����<������<�����<������<�����<�����<�����<����=�����<����=�����<����=�����<����=�����<�����=�����<�����=�����<�����<������<�����#����������!��Ǭ������ ��̪���������Ԫ���������ܪ���������������������������=����=����=�����<����=�����<����=�����<�����=�����<�����=�����<�����<������<�����<������<�����<������<�����<�����<�����<����=�����<����=�����<����=�����<�����=�����<�����=�����<�����<������<�����<������<�����<������<�����<�����<�����<����=�����<����=�����<����=�����<����=�����<�����=�����<�����=�����<�����<������<�����#����������!��Ǭ������ ��̪���������Ԫ���������ܪ����������������������������<�����	����/��Ĭ��	�����-��ˬ��
�����+��Ѫ����+��۪��
������(�������߾�'�����������%�����������$����������#����������!��������� ������������������������ɫ���������Ϫ���������ת��������ު�� ���������!���������:������;�����;�����;�����;������:��ƭ��:��ͫ��:��Ԫ��:��ܪ��:�����:�����:������;�����;�����;�����;�����;��­��:��Ȭ��:��Ϊ��:��ת��:��ߪ��:�����:�����:������;�����;�����;�����<�����<����~�&�����*������)�����)��\���)��x���)������)����"�+��\�+������,��>
���-����j�.����e	���.��Ĭ����<���-��ˬ����͚hDx������+��Ѫ����+��۪��
������(�������߾�'�����������%�����������$����������#����������!��������� ������������������������ɫ���������Ϫ���������ת��������ު�� ���������!���������:������;�����;�����;�����;������:��ƭ��:��ͫ��:��Ԫ��:��ܪ��:�����:�����:������;�����;�����;�����;�����;��­��:��Ȭ��:��Ϊ��:��ת��:��ߪ��:�����:�����:������;�����;�����;�����<�����<����~�&�����*������)�����)��\���)��x���)������)����"�+��\�+������,��>
���-����j�.����e	���.��Ĭ����<���-��ˬ����͚hDx������+��Ѫ����+��۪��
������(�������߾�'�����������%�����������$����������#����������!��������� ������������������������ɫ���������Ϫ���������ת��������ު�� ���������!���������:������;�����;�����;�����;������:��ƭ��:��ͫ��:��Ԫ��:��ܪ��:�����:�����:������;�����;�����;�����;�����;��­��:��Ȭ��:��Ϊ��:��ת��:��ߪ��:�����:�����:������;�����;�����;�����<�����<����~�������=����=�����<�����=�����<������<�����<������<����=�����<�����<�����=�����<����=�����<������<�����=�����<�����<�����<������<��޿�=�����<�����<�����=�����<����=�����<�����<�����=�����<�����<�����<������<�����=�����<������<�����'������=����=�����<�����=�����<������<�����<������<����=�����<�����<�����=�����<����=�����<������<�����=�����<�����<�����<������<��޿�=�����<�����<�����=�����<����=�����<�����<�����=�����<�����<�����<������<�����=�����<������<�����'������=����=�����<�����=�����<������<�����<������<����=�����<�����<�����=�����<����=�����<������<�����=�����<�����<�����<������<��޿�=�����<�����<�����=�����<����=�����<�����<�����=�����<�����<�����<������<�����=�����<������<�����'������������������������������������������������������������������������������ ���������"����������#���������%�������Ĭ��%�������ɫ��'�������Ѫ��(�������٪��*����������+����������,������	������.�����	�����/����	�����;�����Q��������������������� ���������"����������#���������%�������Ĭ��%�������ɫ��'�������Ѫ��(�������٪��*����������+����������,�����������������.���xJ�T�������.���2�Z��.������.���
���,���
�J�,��t���*����(�*������)������)��x���)������)������)���,���E�+������,��W
���-���)�R�/���t	���2����1��5��ўlBt������������������������ ���������"����������#���������%�������Ĭ��%�������ɫ��'�������Ѫ��(�������٪��*����������+����������,�����������������.���xJ�S�������.���2�Z��.������.���
���,���
�J�,��t���*����(�*������)������)��x���)������)������)���,���E�+������,��W
���-���)�R�/���t	���2����1��5��ўlBt���������������<����=�����<�����<�����=�����<����=�����<������<�����=�����<�����<��=������<��޾�=�����<�����<�����=�����<����=�����<�����<����
[�������<����=�����<�����<�����=�����<����=�����<������<�����=�����<�����<��=������<��޾�=�����<�����<�����=�����<����=�����鴁JY����3���R���2���	�5��/������-���
�)��,��7���+���,������*��D���)����M�)����%�*��[�*��D���*��x���*���� ��+������-��:���.���>
�r�1������3����d(x���8�������������<����=�����<�����<�����=�����<����=�����<������<�����=�����<�����<��=������<��޾�=�����<�����<�����=�����<����=�����鴁JY����3���R���2���	�5��/������-���
�)��,��7���+���,������*��D���)����M�)����%�*��[�*��D���*��x���*������+������-��9���.���>
�q�1������3����d(x���8������������������������������������������������������������������������������������������������������������������������������������������������������������������������8�8�8�8����z?=

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')

// make a rect for the background
// d3.drag updates these values behind the scenes
const background = { x: 0, y: 0, x2: 0, y2: 0 }
const radius = 10

//
// setup force simulation
//

const graph = {
  nodes: [
    { id: 0, size: 10 },
    { id: 1, size: 5 },
    { id: 2, size: 2 },
    { id: 3, size: 3 },
    { id: 4, size: 30 },
    { id: 5, size: 40 }
  ],
  links: [
    { source: 0, target: 1 },
    { source: 0, target: 2 },
    { source: 1, target: 0 },
    { source: 3, target: 0 },
    { source: 4, target: 1 }
  ]
}

const simulation = d3
  .forceSimulation()
  .force('link', d3.forceLink().id(d => d.id))
  .force('charge', d3.forceManyBody())
  .force('center', d3.forceCenter(width / 2, height / 2))

simulation.nodes(graph.nodes).on('tick', ticked)

function ticked() {
  render()
}

//
//
//

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)

  context.clearRect(0, 0, width, height)

  // draw a line for each link
  context.strokeStyle = '#aaa'
  context.lineWidth = 1
  context.beginPath()
  graph.links.forEach(link => {
    context.moveTo(
      graph.nodes[link.source].x + background.x,
      graph.nodes[link.source].y + background.y
    )
    context.lineTo(
      graph.nodes[link.target].x + background.x,
      graph.nodes[link.target].y + background.y
    )

    context.stroke()

    // draw a circle for each node
    context.beginPath()
    graph.nodes.forEach(node => {
      context.moveTo(node.x + background.x + radius, node.y + background.y)
      context.arc(
        node.x + background.x,
        node.y + background.y,
        radius,
        0,
        2 * Math.PI
      )
    })
    context.fillStyle = 'red'
    context.fill()
  })
}

function dragSubject() {
  let i
  const n = graph.nodes.length
  let dx
  let dy
  let d2
  let s2 = radius * radius * 4
  let node
  let subject

  for (i = 0; i < n; i += 1) {
    node = graph.nodes[i]
    console.log('node from dragSubject', node)
    dx = d3.event.x - node.x - background.x
    dy = d3.event.y - node.y - background.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 = node
      s2 = d2
    } else if (typeof subject === 'undefined') {
      subject = background
      console.log('background', background)
    }
  }
  return subject
}

function dragStarted() {
  // if (!d3.event.active) simulation.alphaTarget(0.3).restart();
  // 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
}