{
  "$schema": "https://vega.github.io/schema/vega/v6.json",
  "width": 400,
  "height": 275,
  "padding": 0,
  "autosize": "none",
  "signals": [
    {
      "name": "cx",
      "update": "width / 2"
    },
    {
      "name": "cy",
      "update": "height / 2"
    },
    {
      "name": "collideRadius",
      "value": 5,
      "bind": {
        "input": "range",
        "min": 3,
        "max": 20,
        "step": 1,
        "name": "Радиус столкновения"
      }
    },
    {
      "name": "nbodyStrength",
      "value": -10,
      "bind": {
        "input": "range",
        "min": -50,
        "max": 10,
        "step": 1,
        "name": "Сила взаимодействия узлов"
      }
    },
    {
      "name": "linkDistance",
      "value": 15,
      "bind": {
        "input": "range",
        "min": 5,
        "max": 100,
        "step": 1,
        "name": "Длина связей"
      }
    },
    {
      "name": "velocityDecay",
      "value": 0.4,
      "bind": {
        "input": "range",
        "min": 0,
        "max": 1,
        "step": 0.01,
        "name": "Затухание скорости"
      }
    },
    {
      "name": "static",
      "value": true,
      "bind": {
        "input": "checkbox",
        "name": "Статическое моделирование"
      }
    },
    {
      "description": "Переменная состояния фиксации активного узла.",
      "name": "fix",
      "value": 0,
      "on": [
        {
          "events": "symbol:mouseout[!event.buttons], window:mouseup",
          "update": "0"
        },
        {
          "events": "symbol:mouseover",
          "update": "fix || 1"
        },
        {
          "events": "[symbol:mousedown, window:mouseup] > window:mousemove!",
          "update": "2",
          "force": true
        }
      ]
    },
    {
      "description": "Узел графа, с которым пользователь взаимодействовал последним.",
      "name": "node",
      "value": null,
      "on": [
        {
          "events": "symbol:mouseover",
          "update": "fix === 1 ? item() : node"
        }
      ]
    },
    {
      "description": "Признак перезапуска силового моделирования при изменении данных.",
      "name": "restart",
      "value": false,
      "on": [
        {
          "events": {
            "signal": "fix"
          },
          "update": "fix > 1"
        }
      ]
    }
  ],
  "data": [
    {
      "name": "node-data",
      "url": "data/miserables.json",
      "format": {
        "type": "json",
        "property": "nodes"
      }
    },
    {
      "name": "link-data",
      "url": "data/miserables.json",
      "format": {
        "type": "json",
        "property": "links"
      }
    }
  ],
  "scales": [
    {
      "name": "color",
      "type": "ordinal",
      "range": {
        "scheme": "category20c"
      }
    }
  ],
  "marks": [
    {
      "name": "nodes",
      "type": "symbol",
      "zindex": 1,
      "from": {
        "data": "node-data"
      },
      "on": [
        {
          "trigger": "fix",
          "modify": "node",
          "values": "fix === 1 ? {fx:node.x, fy:node.y} : {fx:x(), fy:y()}"
        },
        {
          "trigger": "!fix",
          "modify": "node",
          "values": "{fx: null, fy: null}"
        }
      ],
      "encode": {
        "enter": {
          "fill": {
            "scale": "color",
            "field": "group"
          },
          "stroke": {
            "value": "white"
          }
        },
        "update": {
          "size": {
            "signal": "2 * collideRadius * collideRadius"
          },
          "cursor": {
            "value": "pointer"
          }
        }
      },
      "transform": [
        {
          "type": "force",
          "iterations": 300,
          "velocityDecay": {
            "signal": "velocityDecay"
          },
          "restart": {
            "signal": "restart"
          },
          "static": {
            "signal": "static"
          },
          "forces": [
            {
              "force": "center",
              "x": {
                "signal": "cx"
              },
              "y": {
                "signal": "cy"
              }
            },
            {
              "force": "collide",
              "radius": {
                "signal": "collideRadius"
              }
            },
            {
              "force": "nbody",
              "strength": {
                "signal": "nbodyStrength"
              }
            },
            {
              "force": "link",
              "links": "link-data",
              "distance": {
                "signal": "linkDistance"
              }
            }
          ]
        }
      ]
    },
    {
      "type": "path",
      "from": {
        "data": "link-data"
      },
      "interactive": false,
      "encode": {
        "update": {
          "stroke": {
            "value": "#ccc"
          },
          "strokeWidth": {
            "value": 0.5
          }
        }
      },
      "transform": [
        {
          "type": "linkpath",
          "shape": "line",
          "sourceX": "datum.source.x",
          "sourceY": "datum.source.y",
          "targetX": "datum.target.x",
          "targetY": "datum.target.y"
        }
      ]
    }
  ]
}
