plot({
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": width,
"height": 500,
"padding": {"left": 5},
"autosize": "fit",
"signals": [
{
"name": "margin",
"value": 20
},
{
"name": "down", "value": null,
"on": [
{"events": "mousedown", "update": "xy()"}
]
},
{
"name": "xcur", "value": null,
"on": [
{
"events": "mousedown",
"update": "slice(xdom)"
}
]
},
{
"name": "ycur", "value": null,
"on": [
{
"events": "mousedown",
"update": "slice(ydom)"
}
]
},
{
"name": "zoombox", "value": null,
"on": [
{
"events": "window:mouseup",
"update": "box || zoombox"
}
]
},
{
"name": "box", "value": null,
"on": [
{
"events": [
{
"source": "window",
"type": "mousemove",
"consume": true,
"between": [
{"type": "mousedown", "filter": "event.shiftKey"},
{"source": "window", "type": "mouseup"}]
}
],
"update": "down ? [x(), y()] : null"
},
{
"events": "window:mouseup",
"update": "null"
}
]
},
{
"name": "delta", "value": [0, 0],
"on": [
{
"events": [
{
"source": "window",
"type": "mousemove", "filter": "!event.shiftKey",
"consume": true,
"between": [
{"type": "mousedown", "filter": "!event.shiftKey"},
{"source": "window", "type": "mouseup"}
]
}
],
"update": "down ? [down[0]-x(), y()-down[1]] : [0,0]"
}
]
},
{
"name": "anchor", "value": [0, 0],
"on": [
{
"events": "wheel",
"update": "[invert('xscale', x()), invert('yscale', y())]"
}
]
},
{
"name": "zoom", "value": 1,
"on": [
{
"events": "wheel!",
"force": true,
"update": "pow(1.001, event.deltaY * pow(16, event.deltaMode))"
}
]
},
{
"name": "xdom", "update": "slice(xext)",
"on": [
{
"events": "dblclick",
"update": "slice(xext)"
},
{
"events": {"signal": "delta"},
"update": "[xcur[0] + span(xcur) * delta[0] / width, xcur[1] + span(xcur) * delta[0] / width]"
},
{
"events": {"signal": "zoom"},
"update": "[anchor[0] + (xdom[0] - anchor[0]) * zoom, anchor[0] + (xdom[1] - anchor[0]) * zoom]"
},
{
"events": {"signal": "zoombox"},
"update": "[invert('xscale', min(down[0], zoombox[0])), invert('xscale', max(down[0], zoombox[0]))]"
}
]
},
{
"name": "ydom", "update": "slice(yext)",
"on": [
{
"events": "dblclick",
"update": "slice(yext)"
},
{
"events": {"signal": "delta"},
"update": "[ycur[0] + span(ycur) * delta[1] / height, ycur[1] + span(ycur) * delta[1] / height]"
},
{
"events": {"signal": "zoom"},
"update": "[anchor[1] + (ydom[0] - anchor[1]) * zoom, anchor[1] + (ydom[1] - anchor[1]) * zoom]"
},
{
"events": {"signal": "zoombox"},
"update": "[invert('yscale', max(down[1], zoombox[1])), invert('yscale', min(down[1], zoombox[1]))]"
}
]
},
{
"name": "size",
"update": "clamp(20 / span(xdom), 1, 1000)"
}
],
"data": [
{
"name": "points",
"url": "data/normal-2d.json",
"transform": [
{ "type": "extent", "field": "u", "signal": "xext" },
{ "type": "extent", "field": "v", "signal": "yext" }
]
}
],
"scales": [
{
"name": "xscale", "zero": false,
"domain": {"signal": "xdom"},
"range": "width"
},
{
"name": "yscale", "zero": false,
"domain": {"signal": "ydom"},
"range": "height"
}
],
"axes": [
{
"scale": "xscale",
"orient": "bottom"
},
{
"scale": "yscale",
"orient": "left"
}
],
"marks": [
{
"type": "symbol",
"from": {"data": "points"},
"clip": true,
"encode": {
"enter": {
"fillOpacity": {"value": 0.6},
"fill": {"value": "steelblue"}
},
"update": {
"x": {"scale": "xscale", "field": "u"},
"y": {"scale": "yscale", "field": "v"},
"size": {"signal": "size"}
}
}
},
{
"type": "rect",
"encode": {
"enter": {
"stroke": {"value": "#888"},
"strokeDash": {"value": [3, 3]}
},
"update": {
"strokeOpacity": {"signal": "box ? 1 : 0"},
"x": {"signal": "box ? down[0] : 0"},
"y": {"signal": "box ? down[1] : 0"},
"x2": {"signal": "box ? box[0] : 0"},
"y2": {"signal": "box ? box[1] : 0"}
}
}
}
]
})