Взаимодействие с мышью для перетаскивания точек данных в Vega

Я работаю над более глубоким пониманием взаимодействия на диаграммах Vega. В настоящее время я хотел бы изменить пример Вороного из документации, чтобы вы не добавляете и не удаляете точки, а перетаскиваете существующие точки. Мой код выглядит так:

{
  "$schema": "https://vega.github.io/schema/vega/v4.json",
  "width": 500,
  "height": 200,
  "autosize": "none",

  "signals": [
   {
      "name": "movePoint",
      "on": [
        {
          "events": "[mousedown, mouseup] > mousemove",
          "update": "{u: round(100*invert('xscale', x()))/100, v: round(100*invert('yscale', y()))/100}"
        }
      ]
    }
  ],

  "data": [
    {
      "name": "table",
      "values": [
        {"u": 0.1, "v": 0.1},
        {"u": 0.9, "v": 0.1},
        {"u": 0.1, "v": 0.9},
        {"u": 0.9, "v": 0.9},
        {"u": 0.5, "v": 0.5}
      ],
      "on": [
        {"trigger": "movePoint", "modify": "movePoint", "values": "{u: movePoint.u, v: movePoint.v}"}
      ]
    }
  ],

  "scales": [
    {
      "name": "xscale",
      "domain": [0, 1],
      "range": "width"
    },
    {
      "name": "yscale",
      "domain": [0, 1],
      "range": "height"
    }
  ],

  "marks": [
    {
      "name": "points",
      "type": "symbol",
      "zindex": 1,
      "from": {"data": "table"},
      "interactive": false,
      "encode": {
        "enter": {
          "fill": {"value": "black"},
          "size": {"value": 36},
          "x": {"scale": "xscale", "field": "u"},
          "y": {"scale": "yscale", "field": "v"}
        }
      }
    },
    {
      "type": "path",
      "from": {"data": "points"},
      "encode": {
        "enter": {
          "stroke": {"value": "firebrick"},
          "fill": {"value": "transparent"}
        }
      },
      "transform": [
        {
          "type": "voronoi",
          "x": "datum.x", "y": "datum.y",
          "size": [{"signal": "width"}, {"signal": "height"}]
        }
      ]
    }
  ]
}

Вроде уже сигнал работает хорошо. Я тестировал его с помощью режима отладки Vega, и, похоже, он работает так, как должен:

  • сигнал меняется только тогда, когда мышь перемещается во время ее нажатия
  • значения сигналов находятся в правой системе координат, используемой данными, то есть координаты от 0 до 1

Что не работает, так это взаимодействие: я не могу перетаскивать точки, и данные не меняются при взаимодействии с мышью. Пытался переместить триггер с данных на метки, но тоже не вышло. Что мне нужно сделать, чтобы можно было перетаскивать точки?


person MightyCurious    schedule 07.12.2018    source источник


Ответы (1)


Узнал, как это сделать для себя. Проблема заключалась в том, что сигнал, который я использовал, вычисляет правильные новые координаты, но он не содержит идентификатора перетаскиваемого объекта. Мне показалось, что для этого проще всего добавить отдельный сигнал. Таким образом, вместо одного сигнала «MovePoint» теперь у нас есть «NewPointPosition» (тот же сигнал, новое имя) и «WhichPoint», который содержит идентификатор перетаскиваемого объекта. Возможно, это можно объединить в один сигнал, но, может быть, так легче понять.

Еще один важный момент, которого не хватало в моей первой версии, заключался в том, что для меток «точки» и «путь» требуется предложение «обновить» в «кодировке», а не просто «ввести». В противном случае данные изменятся, но визуализация на это не отреагирует.

Рабочий код выглядит так:

    {
  "$schema": "https://vega.github.io/schema/vega/v4.json",
  "width": 500,
  "height": 200,
  "autosize": "none",

  "signals": [
   {
      "name": "whichPoint",
      "on": [
        {
          "events": "path:click, path:mousemove[event.buttons]{20}",
          "update": "datum.datum"
        }
      ]
    },
   {
      "name": "newPointPosition",
      "on": [
        {
          "events": "path:click, path:mousemove[event.buttons]{20}",
          "update": "{u: invert('xscale', x()), v: invert('yscale', y())}"
        }
      ]
    }
  ],

  "data": [
    {
      "name": "table",
      "values": [
        {"u": 0.1, "v": 0.1},
        {"u": 0.9, "v": 0.1},
        {"u": 0.1, "v": 0.9},
        {"u": 0.9, "v": 0.9},
        {"u": 0.5, "v": 0.5}
      ],
      "on": [
        {"trigger": "whichPoint", "modify": "whichPoint", "values": "{u: newPointPosition.u, v:newPointPosition.v}"}
      ]
    }
  ],

  "scales": [
    {
      "name": "xscale",
      "domain": [0, 1],
      "range": "width"
    },
    {
      "name": "yscale",
      "domain": [0, 1],
      "range": "height"
    }
  ],

  "marks": [
    {
      "name": "points",
      "type": "symbol",
      "zindex": 1,
      "from": {"data": "table"},
      "encode": {
        "enter": {
          "fill": {"value": "black"},
          "size": {"value": 36},
          "x": {"scale": "xscale", "field": "u"},
          "y": {"scale": "yscale", "field": "v"}
        },
        "update": {
          "fill": {"value": "black"},
          "size": {"value": 36},
          "x": {"scale": "xscale", "field": "u"},
          "y": {"scale": "yscale", "field": "v"}
        }
      }
    },
    {
      "type": "path",
      "from": {"data": "points"},
      "encode": {
        "enter": {
          "stroke": {"value": "firebrick"},
          "fill": {"value": "transparent"}
        },
        "update": {
          "stroke": {"value": "firebrick"},
          "fill": {"value": "transparent"}
        }
      },
      "transform": [
        {
          "type": "voronoi",
          "x": "datum.x", "y": "datum.y",
          "size": [{"signal": "width"}, {"signal": "height"}]
        }
      ]
    }
  ]
}
person MightyCurious    schedule 11.12.2018