{
  "$schema": "https://vega.github.io/schema/vega/v4.json",
  "width": 700,
  "height": 400,
  "padding": {
    "top": 25,
    "left": 0,
    "right": 0,
    "bottom": 0
  },
  "autosize": "none",
  "signals": [
    {
      "name": "hover",
      "value": null,
      "on": [
        {
          "events": "symbol:mouseover",
          "update": "datum"
        },
        {
          "events": "symbol:mouseout",
          "update": "null"
        }
      ]
    },
    {
      "name": "title",
      "value": "",
      "update": "hover ? hover.name : '' "
    },
    {
      "name": "cx",
      "update": "width / 2"
    },
    {
      "name": "cy",
      "update": "height / 2"
    },
    {
      "name": "nodeRadius",
      "value": 10,
      "bind": {
        "input": "range",
        "min": 1,
        "max": 50,
        "step": 1
      }
    },
    {
      "name": "nodeCharge",
      "value": -70,
      "bind": {
        "input": "range",
        "min": -100,
        "max": 10,
        "step": 1
      }
    },
    {
      "name": "linkDistance",
      "value": 70,
      "bind": {
        "input": "range",
        "min": 5,
        "max": 100,
        "step": 1
      }
    },
    {
      "name": "static",
      "value": false,
      "bind": {
        "input": "checkbox"
      }
    },
    {
      "description": "State variable for active node fix status.",
      "name": "fix",
      "value": false,
      "on": [
        {
          "events": "symbol:mouseout[!event.buttons], window:mouseup",
          "update": "false"
        },
        {
          "events": "symbol:mouseover",
          "update": "fix || true"
        },
        {
          "events": "[symbol:mousedown, window:mouseup] > window:mousemove!",
          "update": "xy()",
          "force": true
        }
      ]
    },
    {
      "description": "Graph node most recently interacted with.",
      "name": "node",
      "value": null,
      "on": [
        {
          "events": "symbol:mouseover",
          "update": "fix === true ? item() : node"
        }
      ]
    },
    {
      "description": "Flag to restart Force simulation upon data changes.",
      "name": "restart",
      "value": false,
      "on": [
        {
          "events": {
            "signal": "fix"
          },
          "update": "fix && fix.length"
        }
      ]
    }
  ],
  "data": [
    {
      "name": "node-data",
      "url": "/relations_zeroed",
      "format": {
        "type": "json",
        "property": "nodes"
      }
    },
    {
      "name": "link-data",
      "url": "/relations_zeroed",
      "format": {
        "type": "json",
        "property": "links"
      }
    }
  ],
  "scales": [
    {
      "name": "color",
      "type": "ordinal",
      "domain": {
        "data": "node-data",
        "field": "group"
      },
      "range": {
        "scheme": "category20c"
      }
    }
  ],
  "marks": [
    {
      "name": "nodes-group",
      "type": "group",
      "zindex": 1,
      "from": {
        "data": "node-data"
      },
      "marks": [
        {
          "name": "nodes",
          "type": "symbol",
          "encode": {
            "enter": {
              "fill": {
                "scale": "color",
                "field": {"parent":  "group"}
              },
              "stroke": {
                "value": "white"
              }
            },
            "update": {
              "size": {
                "signal": "2 * nodeRadius * nodeRadius"
              },
              "cursor": {
                "value": "pointer"
              }
            }
          }
        },
        {
          "type": "text",
          "interactive": false,
          "encode": {
            "enter": {
              "fill": {
                "value": "black"
              },
              "fontSize": {
                "value": 12
              },
              "align": {
                "value": "center"
              },
              "text": {
                "field": {"parent": "name"}
              },
              "y": {
                "value": -10
              }
            }
          }
        }
      ],
      "on": [
        {
          "trigger": "fix",
          "modify": "node",
          "values": "fix === true ? {fx: node.x, fy: node.y} : {fx: fix[0], fy: fix[1]}"
        },
        {
          "trigger": "!fix",
          "modify": "node",
          "values": "{fx: null, fy: null}"
        }
      ],
      "transform": [
        {
          "type": "force",
          "iterations": 300,
          "restart": {
            "signal": "restart"
          },
          "static": {
            "signal": "static"
          },
          "signal": "force",
          "forces": [
            {
              "force": "center",
              "x": {
                "signal": "cx"
              },
              "y": {
                "signal": "cy"
              }
            },
            {
              "force": "collide",
              "radius": {
                "signal": "nodeRadius"
              }
            },
            {
              "force": "nbody",
              "strength": {
                "signal": "nodeCharge"
              }
            },
            {
              "force": "link",
              "links": "link-data",
              "distance": {
                "signal": "linkDistance"
              }
            }
          ]
        }
      ]
    },
    {
      "type": "path",
      "from": {
        "data": "link-data"
      },
      "interactive": false,
      "encode": {
        "update": {
          "stroke": {
            "value": "#ccc"
          },
          "strokeWidth": {
            "value": 1
          }
        }
      },
      "transform": [
        {
          "type": "linkpath",
          "require": {
            "signal": "force"
          },
          "shape": "line",
          "sourceX": "datum.source.x",
          "sourceY": "datum.source.y",
          "targetX": "datum.target.x",
          "targetY": "datum.target.y"
        }
      ]
    },
    {
      "type": "text",
      "interactive": false,
      "encode": {
        "enter": {
          "x": {
            "signal": "width",
            "offset": -5
          },
          "y": {
            "value": 0
          },
          "fill": {
            "value": "black"
          },
          "fontSize": {
            "value": 20
          },
          "align": {
            "value": "right"
          }
        },
        "update": {
          "text": {
            "signal": "title"
          }
        }
      }
    }
  ]
}
