Created
October 22, 2019 17:56
-
-
Save guru-florida/378076f154c10c6d171608c1e82b2e3c to your computer and use it in GitHub Desktop.
Smooth Timeline control in Vega
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "$schema": "https://vega.github.io/schema/vega/v5.json", | |
| "width": 1500, | |
| "height": 50, | |
| "padding": 15, | |
| "signals": [ | |
| { | |
| "name": "rangeLimits", | |
| "value": [30, 120] | |
| }, | |
| { | |
| "name": "scrollock", | |
| "value": false, | |
| "on": [{ | |
| "events": "window:keyup![!event.shiftKey && !event.ctrlKey && event.keyCode==76]", | |
| "update": "!scrollock" | |
| }] | |
| }, | |
| { | |
| "name": "tsvelocity", "value": 0, | |
| "description": "current velocity of the timeline (ex. throwing the timeline)", | |
| "on": [{ | |
| "events": { | |
| "type": "timer", | |
| "throttle": 100 | |
| }, | |
| "update": "abs(tsvelocity) > 60000 ? tsvelocity * tsacc : 0" | |
| }, { | |
| "events": "mousemove[event.buttons]", | |
| "update": "scrollock ? 0 :-event.movementX * 400000" | |
| }] | |
| }, { | |
| "name": "tsacc", "value": 0.75, | |
| "description": "deaccelleration parameter controls how quickly the the timeline stops after a throw" | |
| }, | |
| { | |
| "name": "tsrange", "value": 120, | |
| "description": "zoom setting, larger values means we are zooming out on the timeline", | |
| "on": [{ | |
| "events": "wheel", | |
| "update": "clamp(tsrange + (event.deltaY * 5), rangeLimits[0], rangeLimits[1])" | |
| }] | |
| }, | |
| { | |
| "name": "tspick", "value": 0, | |
| "on":[{ | |
| "events": "mousedown", | |
| "update": "floor(invert('lin_timescale', clamp(x(), 0, width)))" | |
| }, { | |
| "events": "mouseup", | |
| "update": "0" | |
| }] | |
| }, | |
| { | |
| "name": "centerts", "value": 1568164000000, | |
| "description": "timestamp that represents the center, the range is then extended to the left and right", | |
| "on": [{ | |
| "events": "mousemove[event.buttons]", | |
| "update": "(tspick===0 || scrollock) ? centerts : centerts + (tspick - invert('lin_timescale', clamp(x(), 0, width)))" | |
| }, { | |
| "events": { | |
| "type": "timer", | |
| "throttle": 33 | |
| }, | |
| "update": "(tspick > 0) ? centerts : floor(centerts + tsvelocity/33)" | |
| }, { | |
| "events": "window:keyup![!event.shiftKey && (event.keyCode>48) && (event.keyCode<59) ]", | |
| "update": "warn('goto ', (isDefined(data('bookmarks')[event.keyCode - 49]) && data('bookmarks')[event.keyCode - 49].ts) ? data('bookmarks')[event.keyCode - 49].ts : centerts)" | |
| }, { | |
| "events": "window:keyup![event.shiftKey && event.keyCode==37]", | |
| "update": "centerts - 86400000" | |
| }, { | |
| "events": "window:keyup![event.shiftKey && event.keyCode==39]", | |
| "update": "centerts + 86400000" | |
| }, { | |
| "events": "window:keyup![!event.shiftKey && event.keyCode==37]", | |
| "update": "centerts - 3600000" | |
| }, { | |
| "events": "window:keyup![!event.shiftKey && event.keyCode==39]", | |
| "update": "centerts + 3600000" | |
| },{ | |
| "events": "window:keyup![!event.shiftKey && event.keyCode==78]", | |
| "update": "1569797913000" | |
| },{ | |
| "events": "mousedown", | |
| "update": "(datum && datum.shortcut && datum.ts) ? datum.ts : centerts" | |
| }] | |
| }, | |
| { | |
| "name": "startts", "value": 1568152000000, "update": "centerts - (tsrange * 30000)" | |
| }, | |
| { | |
| "name": "endts", "value": 1568152000000, "update": "centerts + (tsrange * 30000)" | |
| }, | |
| { | |
| "name": "tickMinor", "update": "(tsrange < 60) ? 5 : (tsrange < 120) ? 10 : 15" | |
| }, | |
| { | |
| "name": "tickMajor", "update": "tickMinor * 4" | |
| }, | |
| { | |
| "name": "savebookmark", | |
| "on": [{ | |
| "events": "window:keydown[event.shiftKey && (event.keyCode>48) && (event.keyCode<59) ]", | |
| "update": "warn('save ', event.keyCode - 49, (isDefined(data('bookmarks')[event.keyCode - 49])) ? data('bookmarks')[event.keyCode - 49] : null)" | |
| }, { | |
| "events": "window:keyup[event.shiftKey && (event.keyCode>48) && (event.keyCode<59) ]", | |
| "update": "null" | |
| }] | |
| }, | |
| { | |
| "name": "bmspacing", "value": 30 | |
| } | |
| ], | |
| "data": [{ | |
| "name": "window", | |
| "values": [ | |
| { "from": 1000, "to": 1567296000000, "fill": "#222", "radius": 0 }, | |
| { "from": 1569801600000, "to": 9569801600000, "fill": "#5511117b", "radius": 0 } | |
| ] | |
| }, { | |
| "name": "bookmarks", | |
| "on":[{ | |
| "trigger": "savebookmark", | |
| "modify": "savebookmark", | |
| "values": "{ ts: centerts }" | |
| }], | |
| "values": [ | |
| { "shortcut": "1", "ts": 1568159000000 }, | |
| { "shortcut": "2", "ts": 1568162000000 }, | |
| { "shortcut": "3", "ts": 1568166000000 }, | |
| { "shortcut": "4", "ts": 1569024000000 }, | |
| { "shortcut": "5", "ts": 0 }, | |
| { "shortcut": "6", "ts": 0 }, | |
| { "shortcut": "7", "ts": 0 }, | |
| { "shortcut": "8", "ts": 0 }, | |
| { "shortcut": "9", "ts": 0 } | |
| ] | |
| }, { | |
| "name": "BMLT", | |
| "source": "bookmarks", | |
| "transform": [{ | |
| "type": "filter", | |
| "expr": "datum.ts>0 && datum.ts < startts" | |
| }] | |
| }, { | |
| "name": "BMV", | |
| "source": "bookmarks", | |
| "transform": [{ | |
| "type": "filter", | |
| "expr": "datum.ts > startts && datum.ts < endts" | |
| }] | |
| }, { | |
| "name": "BMGT", | |
| "source": "bookmarks", | |
| "transform": [{ | |
| "type": "filter", | |
| "expr": "datum.ts > endts" | |
| }] | |
| }], | |
| "scales": [ | |
| { | |
| "name": "lin_timescale", | |
| "type": "linear", | |
| "domain": [{"signal": "startts"}, {"signal": "endts"}], | |
| "nice": false, | |
| "zero": false, | |
| "range": "width" | |
| }, { | |
| "name": "timescale", | |
| "type": "time", | |
| "domain": { "signal": "domain('lin_timescale')" }, | |
| "nice": false, | |
| "clamp": true, | |
| "range": "width" | |
| }, { | |
| "name": "bands", | |
| "type": "band", | |
| "paddingInner": 0.04, | |
| "domain": [0, 1, 2, 3, 4, 5], | |
| "range": "height" | |
| } | |
| ], | |
| "axes": [ | |
| { | |
| "orient": "top", "scale": "timescale", "domain": false, | |
| "tickCount": { "interval": "minute", "step": 5 }, | |
| "labels": false, | |
| "grid": true, | |
| "gridWidth": 2, | |
| "gridColor": "#888", | |
| "zindex": -1, | |
| "encode": { | |
| "grid": { | |
| "update": { | |
| "y": { "scale": "bands", "value": 2 }, | |
| "y2": { "scale": "bands", "value": 3 } | |
| } | |
| } | |
| } | |
| }, | |
| { | |
| "orient": "top", "scale": "timescale", "domain": false, | |
| "tickCount": { "interval": "minute", "step": 15 }, | |
| "labelOverlap": "greedy", | |
| "grid": true, | |
| "gridWidth": 2, | |
| "gridColor": "#888", | |
| "zindex": -1, | |
| "format": "%H:%M", | |
| "encode": { | |
| "grid": { | |
| "update": { | |
| "y": { "scale": "bands", "value": 1 }, | |
| "y2": { "scale": "bands", "value": 4 } | |
| } | |
| } | |
| } | |
| }, | |
| { | |
| "orient": "bottom", "scale": "timescale", "domain": false, | |
| "tickCount": { "interval": "hour", "step": 1 }, | |
| "labels": true, | |
| "labelColor": "white", | |
| "grid": true, | |
| "gridWidth": 3, | |
| "gridColor": "#888", | |
| "zindex": -1, | |
| "format": "%b%d %-I%p", | |
| "encode": { | |
| "labels": { | |
| "update": { | |
| "y": { "value": 9 }, | |
| "y2": { "scale": "bands", "value": 1 } | |
| } | |
| } | |
| } | |
| } | |
| ], | |
| "marks": [ | |
| { | |
| "name": "bars", | |
| "from": {"data": "window"}, | |
| "type": "rect", | |
| "encode": { | |
| "enter": { | |
| "y": {"scale": "bands", "value": 0, "offset": -4 }, | |
| "height": {"scale": "bands", "band": 6, "offset": 9 } | |
| }, | |
| "update": { | |
| "x": {"scale": "timescale", "field": "from"}, | |
| "x2": {"scale": "timescale", "field": "to"}, | |
| "cornerRadius": { "field": "radius" }, | |
| "fill": { "field": "fill"}, | |
| "stroke": { "field": "stroke"}, | |
| "strokeWidth": { "field": "strokeWidth"} | |
| } | |
| } | |
| }, | |
| { | |
| "name": "bookmarksGroup", | |
| "type": "group", | |
| "signals": [{ | |
| "name": "bmlt_width", | |
| "update": "data('BMLT').length * bmspacing" | |
| }, { | |
| "name": "bmgt_width", | |
| "update": "data('BMGT').length * bmspacing" | |
| }], | |
| "scales": [{ | |
| "name": "bmlt_scale", | |
| "type": "point", | |
| "align": 0, | |
| "domain": { | |
| "data": "BMLT", | |
| "field": "shortcut", | |
| "sort": {"op": "median", "field": "ts", "order": "ascending"} | |
| }, | |
| "range": { "step": { "signal": "bmspacing" } } | |
| }, { | |
| "name": "bmgt_scale", | |
| "type": "point", | |
| "align": 0, | |
| "domain": { | |
| "data": "BMGT", | |
| "field": "shortcut", | |
| "sort": {"op": "median", "field": "ts", "order": "descending"} | |
| }, | |
| "range": { "step": { "signal": "bmspacing" } } | |
| }, { | |
| "name": "timescale_bmv", | |
| "type": "linear", | |
| "domain": [ | |
| { "signal": "invert('lin_timescale', bmlt_width)" }, | |
| { "signal": "invert('lin_timescale', width - bmgt_width )" } | |
| ], | |
| "nice": false, | |
| "clamp": true, | |
| "zero": false, | |
| "range": [{ "signal": "bmlt_width" }, { "signal": "width - bmgt_width" }] | |
| }], | |
| "marks": [ | |
| { | |
| "name": "BMPointers", | |
| "from": {"data": "BMV"}, | |
| "type": "symbol", | |
| "encode": { | |
| "enter": { | |
| "shape": {"value": "wedge"}, | |
| "y": {"scale": "bands", "value": 4, "offset": 7 }, | |
| "size": { "value": 500 }, | |
| "zindex": { "value": 5 }, | |
| "fill": { "value": "#00bfff"} | |
| }, | |
| "update": { | |
| "x": {"scale": "timescale", "field": "ts" } | |
| } | |
| } | |
| }, | |
| { | |
| "name": "BMLTSquares", | |
| "from": {"data": "BMLT"}, | |
| "type": "rect", | |
| "encode": { | |
| "enter": { | |
| "y": {"scale": "bands", "value": 5 }, | |
| "width": { "value": 20 }, | |
| "height": { "value": 20 }, | |
| "fill": { "value": "#00bfff"}, | |
| "zindex": { "value": 5 }, | |
| "cornerRadius": { "value": 4 } | |
| }, | |
| "update": { | |
| "x": { "scale": "bmlt_scale", "field": "shortcut", "offset": -10 } | |
| } | |
| } | |
| }, { | |
| "name": "BMLTLabels", | |
| "from": {"data": "BMLT"}, | |
| "type": "text", | |
| "encode": { | |
| "enter": { | |
| "text": {"field": "shortcut"}, | |
| "align": { "value": "center" }, | |
| "baseline": { "value": "top" }, | |
| "fontSize": { "value": 14 }, | |
| "y": {"scale": "bands", "value": 5, "offset": 4 }, | |
| "size": { "value": 200 }, | |
| "fill": { "value": "white"} | |
| }, | |
| "update": { | |
| "x": { "scale": "bmlt_scale", "field": "shortcut" } | |
| } | |
| } | |
| }, | |
| { | |
| "name": "BMCVSquares", | |
| "from": {"data": "BMV"}, | |
| "type": "rect", | |
| "encode": { | |
| "enter": { | |
| "y": {"scale": "bands", "value": 5 }, | |
| "width": { "value": 20 }, | |
| "height": { "value": 20 }, | |
| "fill": { "value": "#00bfff"}, | |
| "zindex": { "value": 5 }, | |
| "cornerRadius": { "value": 4 } | |
| }, | |
| "update": { | |
| "x": {"scale": "timescale_bmv", "field": "ts", "offset": -10 } | |
| } | |
| } | |
| }, { | |
| "name": "BMCVLabels", | |
| "from": {"data": "BMV"}, | |
| "type": "text", | |
| "encode": { | |
| "enter": { | |
| "text": {"field": "shortcut"}, | |
| "align": { "value": "center" }, | |
| "baseline": { "value": "top" }, | |
| "fontSize": { "value": 14 }, | |
| "y": {"scale": "bands", "value": 5, "offset": 4 }, | |
| "size": { "value": 200 }, | |
| "zindex": { "value": 5 }, | |
| "fill": { "value": "white"} | |
| }, | |
| "update": { | |
| "x": {"scale": "timescale_bmv", "field": "ts" } | |
| } | |
| } | |
| }, | |
| { | |
| "name": "BMGTSquares", | |
| "from": {"data": "BMGT"}, | |
| "type": "rect", | |
| "zindex": { "value": 50 }, | |
| "encode": { | |
| "enter": { | |
| "y": {"scale": "bands", "value": 5 }, | |
| "width": { "value": 20 }, | |
| "height": { "value": 20 }, | |
| "fill": { "value": "#00bfff"}, | |
| "zindex": { "value": 5 }, | |
| "cornerRadius": { "value": 4 } | |
| }, | |
| "update": { | |
| "x": { "signal": "width-10", "offset": { "scale": "bmgt_scale", "field": "shortcut", "mult": -1 } } | |
| } | |
| } | |
| }, { | |
| "name": "BMGTLabels", | |
| "from": {"data": "BMGT"}, | |
| "type": "text", | |
| "encode": { | |
| "enter": { | |
| "text": {"field": "shortcut"}, | |
| "align": { "value": "center" }, | |
| "baseline": { "value": "top" }, | |
| "fontSize": { "value": 14 }, | |
| "y": {"scale": "bands", "value": 5, "offset": 4 }, | |
| "size": { "value": 200 }, | |
| "zindex": { "value": 5 }, | |
| "fill": { "value": "white"} | |
| }, | |
| "update": { | |
| "x": { "signal": "width", "offset": { "scale": "bmgt_scale", "field": "shortcut", "mult": -1 } } | |
| } | |
| } | |
| } | |
| ] | |
| }] | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment