我正在努力更深入地了解Vega图中的交互。当前,我想修改Voronoi example from the documentation,以便您不添加和删除点,而是拖动现有点。我的代码如下:
{
"$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 :(得分:0)
我发现了如何为自己做这件事。问题是我使用的信号可以计算正确的新坐标,但是它不包含要拖动的对象的ID。我发现最简单的方法是为此添加一个单独的信号。因此,现在有了一个“ NewPointPosition”(相同的信号,新名称)和“ WhichPoint”,而不是一个“ MovePoint”信号,其中包含要拖动的对象的ID。也许可以将其合并为一个信号,但这样更容易理解。
我的第一个版本中缺少的另一个重要点是,“ points”和“ path”标记需要在“ encode”中使用“ update”子句,而不仅仅是“ enter”子句。否则,数据将发生变化,但是可视化将不会对此做出反应。
工作代码如下:
{
"$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"}]
}
]
}
]
}