From 0a09ec3b0d1e617eebe1cec48e6bc57d0d7bf580 Mon Sep 17 00:00:00 2001 From: Arvind Satyanarayan Date: Fri, 24 Feb 2023 12:53:50 -0500 Subject: [PATCH] feat: enable interval selections for cartographic projections (#6953) Co-authored-by: GitHub Actions Bot --- examples/compiled/airport_connections.svg | 2 +- examples/compiled/airport_connections.vg.json | 3 +- examples/compiled/arc_donut.vg.json | 1 + examples/compiled/arc_facet.vg.json | 1 + examples/compiled/arc_ordinal_theta.vg.json | 1 + examples/compiled/arc_params.vg.json | 2 + examples/compiled/arc_pie.vg.json | 1 + examples/compiled/arc_pie_pyramid.vg.json | 1 + examples/compiled/arc_radial.vg.json | 1 + .../compiled/arc_radial_histogram.vg.json | 1 + examples/compiled/geo_choropleth.vg.json | 1 + examples/compiled/geo_circle.vg.json | 1 + examples/compiled/geo_constant_value.vg.json | 1 + .../compiled/geo_custom_projection.vg.json | 1 + examples/compiled/geo_graticule.vg.json | 1 + .../compiled/geo_graticule_object.vg.json | 1 + examples/compiled/geo_layer.vg.json | 1 + .../compiled/geo_layer_line_london.vg.json | 1 + examples/compiled/geo_line.vg.json | 1 + .../compiled/geo_params_projections.vg.json | 1 + examples/compiled/geo_point.vg.json | 1 + examples/compiled/geo_repeat.vg.json | 3 + examples/compiled/geo_rule.vg.json | 1 + examples/compiled/geo_sphere.vg.json | 1 + examples/compiled/geo_text.vg.json | 1 + examples/compiled/geo_trellis.vg.json | 1 + .../compiled/interactive_1d_geo_brush.png | Bin 0 -> 144635 bytes .../compiled/interactive_1d_geo_brush.svg | 1 + .../compiled/interactive_1d_geo_brush.vg.json | 346 ++++ .../interactive_airport_crossfilter.png | Bin 0 -> 76040 bytes .../interactive_airport_crossfilter.svg | 1 + .../interactive_airport_crossfilter.vg.json | 841 ++++++++ .../interactive_global_development.vg.json | 2 +- examples/compiled/layer_arc_label.vg.json | 1 + .../layer_point_line_regression.vg.json | 2 +- .../compiled/point_angle_windvector.vg.json | 1 + examples/compiled/point_overlap.vg.json | 1 + .../compiled/test_single_point_color.vg.json | 1 + .../specs/interactive_1d_geo_brush.vl.json | 38 + .../interactive_airport_crossfilter.vl.json | 115 ++ ...nteractive_1d_geo_brush_normalized.vl.json | 37 + ...ive_airport_crossfilter_normalized.vl.json | 125 ++ src/compile/mark/mark.ts | 2 +- src/compile/selection/assemble.ts | 14 +- src/compile/selection/index.ts | 8 +- src/compile/selection/inputs.ts | 3 +- src/compile/selection/interval.ts | 323 ++-- src/compile/selection/legends.ts | 4 +- src/compile/selection/parse.ts | 5 +- src/compile/selection/project.ts | 61 +- src/compile/selection/scales.ts | 3 +- src/compile/selection/translate.ts | 43 +- src/compile/selection/zoom.ts | 37 +- src/compile/unit.ts | 2 +- src/log/message.ts | 3 +- test-runtime/interval.test.ts | 24 +- .../resources/interval/translate/geo-0.svg | 1 + .../resources/interval/translate/geo-1.svg | 1 + .../resources/interval/translate/geo-2.svg | 1 + .../resources/interval/unit/geo_0.svg | 1 + .../resources/interval/unit/geo_1.svg | 1 + .../resources/interval/zoom/geo-0.svg | 1 + .../resources/interval/zoom/geo-1.svg | 1 + .../resources/interval/zoom/geo-2.svg | 1 + test-runtime/translate.test.ts | 292 +-- test-runtime/util.ts | 76 +- test-runtime/zoom.test.ts | 324 ++-- test/compile/model.test.ts | 2 +- test/compile/selection/interval.test.ts | 1716 ++++++++++------- test/compile/selection/parse.test.ts | 64 +- 70 files changed, 3300 insertions(+), 1258 deletions(-) create mode 100644 examples/compiled/interactive_1d_geo_brush.png create mode 100644 examples/compiled/interactive_1d_geo_brush.svg create mode 100644 examples/compiled/interactive_1d_geo_brush.vg.json create mode 100644 examples/compiled/interactive_airport_crossfilter.png create mode 100644 examples/compiled/interactive_airport_crossfilter.svg create mode 100644 examples/compiled/interactive_airport_crossfilter.vg.json create mode 100644 examples/specs/interactive_1d_geo_brush.vl.json create mode 100644 examples/specs/interactive_airport_crossfilter.vl.json create mode 100644 examples/specs/normalized/interactive_1d_geo_brush_normalized.vl.json create mode 100644 examples/specs/normalized/interactive_airport_crossfilter_normalized.vl.json create mode 100644 test-runtime/resources/interval/translate/geo-0.svg create mode 100644 test-runtime/resources/interval/translate/geo-1.svg create mode 100644 test-runtime/resources/interval/translate/geo-2.svg create mode 100644 test-runtime/resources/interval/unit/geo_0.svg create mode 100644 test-runtime/resources/interval/unit/geo_1.svg create mode 100644 test-runtime/resources/interval/zoom/geo-0.svg create mode 100644 test-runtime/resources/interval/zoom/geo-1.svg create mode 100644 test-runtime/resources/interval/zoom/geo-2.svg diff --git a/examples/compiled/airport_connections.svg b/examples/compiled/airport_connections.svg index 725e6af54d0..3489a11df37 100644 --- a/examples/compiled/airport_connections.svg +++ b/examples/compiled/airport_connections.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/examples/compiled/airport_connections.vg.json b/examples/compiled/airport_connections.vg.json index 80ac0546939..364fc421b5c 100644 --- a/examples/compiled/airport_connections.vg.json +++ b/examples/compiled/airport_connections.vg.json @@ -5,6 +5,7 @@ "padding": 5, "width": 900, "height": 500, + "style": "view", "data": [ {"name": "org_store"}, { @@ -177,7 +178,7 @@ "name": "layer_0_marks", "type": "shape", "style": ["geoshape"], - "interactive": false, + "interactive": true, "from": {"data": "source_0"}, "encode": { "update": { diff --git a/examples/compiled/arc_donut.vg.json b/examples/compiled/arc_donut.vg.json index 389e13d5ef6..60ec25b55fa 100644 --- a/examples/compiled/arc_donut.vg.json +++ b/examples/compiled/arc_donut.vg.json @@ -5,6 +5,7 @@ "padding": 5, "width": 200, "height": 200, + "style": "view", "data": [ { "name": "source_0", diff --git a/examples/compiled/arc_facet.vg.json b/examples/compiled/arc_facet.vg.json index 89f6d05fb81..d88dc740bcb 100644 --- a/examples/compiled/arc_facet.vg.json +++ b/examples/compiled/arc_facet.vg.json @@ -72,6 +72,7 @@ { "name": "cell", "type": "group", + "style": "view", "from": { "facet": {"name": "facet", "data": "source_0", "groupby": ["year"]} }, diff --git a/examples/compiled/arc_ordinal_theta.vg.json b/examples/compiled/arc_ordinal_theta.vg.json index d89f45594fd..ed841d44a4e 100644 --- a/examples/compiled/arc_ordinal_theta.vg.json +++ b/examples/compiled/arc_ordinal_theta.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 200, "height": 200, + "style": "view", "data": [ { "name": "source_0", diff --git a/examples/compiled/arc_params.vg.json b/examples/compiled/arc_params.vg.json index 14d707be610..0af536c4cd1 100644 --- a/examples/compiled/arc_params.vg.json +++ b/examples/compiled/arc_params.vg.json @@ -80,6 +80,7 @@ "type": "group", "name": "concat_0_group", "title": {"text": "Single Arc", "frame": "group"}, + "style": "view", "encode": { "update": { "width": {"signal": "childWidth"}, @@ -114,6 +115,7 @@ "type": "group", "name": "concat_1_group", "title": {"text": "Stacked Arcs", "frame": "group"}, + "style": "view", "encode": { "update": { "width": {"signal": "childWidth"}, diff --git a/examples/compiled/arc_pie.vg.json b/examples/compiled/arc_pie.vg.json index f55c0ef74f3..eb9e150a1b2 100644 --- a/examples/compiled/arc_pie.vg.json +++ b/examples/compiled/arc_pie.vg.json @@ -5,6 +5,7 @@ "padding": 5, "width": 200, "height": 200, + "style": "view", "data": [ { "name": "source_0", diff --git a/examples/compiled/arc_pie_pyramid.vg.json b/examples/compiled/arc_pie_pyramid.vg.json index e39ac16596e..e49b5d398dd 100644 --- a/examples/compiled/arc_pie_pyramid.vg.json +++ b/examples/compiled/arc_pie_pyramid.vg.json @@ -5,6 +5,7 @@ "padding": 5, "width": 200, "height": 200, + "style": "view", "data": [ { "name": "source_0", diff --git a/examples/compiled/arc_radial.vg.json b/examples/compiled/arc_radial.vg.json index eb72aad8ad4..8a23181fe67 100644 --- a/examples/compiled/arc_radial.vg.json +++ b/examples/compiled/arc_radial.vg.json @@ -5,6 +5,7 @@ "padding": 5, "width": 200, "height": 200, + "style": "view", "data": [ {"name": "source_0", "values": [12, 23, 47, 6, 52, 19]}, { diff --git a/examples/compiled/arc_radial_histogram.vg.json b/examples/compiled/arc_radial_histogram.vg.json index 485e9da81f5..3211200218d 100644 --- a/examples/compiled/arc_radial_histogram.vg.json +++ b/examples/compiled/arc_radial_histogram.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 200, "height": 200, + "style": "view", "data": [ { "name": "source_0", diff --git a/examples/compiled/geo_choropleth.vg.json b/examples/compiled/geo_choropleth.vg.json index b6b9285091c..857c5be0c14 100644 --- a/examples/compiled/geo_choropleth.vg.json +++ b/examples/compiled/geo_choropleth.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 500, "height": 300, + "style": "view", "data": [ { "name": "source_1", diff --git a/examples/compiled/geo_circle.vg.json b/examples/compiled/geo_circle.vg.json index d2417136865..928b5138eac 100644 --- a/examples/compiled/geo_circle.vg.json +++ b/examples/compiled/geo_circle.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 500, "height": 300, + "style": "view", "data": [ { "name": "source_0", diff --git a/examples/compiled/geo_constant_value.vg.json b/examples/compiled/geo_constant_value.vg.json index b26c519b0ae..ebf40947e06 100644 --- a/examples/compiled/geo_constant_value.vg.json +++ b/examples/compiled/geo_constant_value.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 500, "height": 300, + "style": "view", "data": [ {"name": "source_0", "url": "data/airports.csv", "format": {"type": "csv"}}, { diff --git a/examples/compiled/geo_custom_projection.vg.json b/examples/compiled/geo_custom_projection.vg.json index ccbb878b688..11e3a1680d0 100644 --- a/examples/compiled/geo_custom_projection.vg.json +++ b/examples/compiled/geo_custom_projection.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 900, "height": 560, + "style": "view", "data": [ { "name": "source_0", diff --git a/examples/compiled/geo_graticule.vg.json b/examples/compiled/geo_graticule.vg.json index b99cca1b042..4383dbdff48 100644 --- a/examples/compiled/geo_graticule.vg.json +++ b/examples/compiled/geo_graticule.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 200, "height": 200, + "style": "view", "data": [{"name": "source_0", "transform": [{"type": "graticule"}]}], "projections": [ { diff --git a/examples/compiled/geo_graticule_object.vg.json b/examples/compiled/geo_graticule_object.vg.json index 3f9782c7917..80d5094d91f 100644 --- a/examples/compiled/geo_graticule_object.vg.json +++ b/examples/compiled/geo_graticule_object.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 200, "height": 200, + "style": "view", "data": [ {"name": "source_0", "transform": [{"type": "graticule", "step": [15, 15]}]} ], diff --git a/examples/compiled/geo_layer.vg.json b/examples/compiled/geo_layer.vg.json index 7ca74aec0ff..b2b66955c18 100644 --- a/examples/compiled/geo_layer.vg.json +++ b/examples/compiled/geo_layer.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 500, "height": 300, + "style": "view", "data": [ { "name": "source_0", diff --git a/examples/compiled/geo_layer_line_london.vg.json b/examples/compiled/geo_layer_line_london.vg.json index 2811207595d..c2bf00c0f35 100644 --- a/examples/compiled/geo_layer_line_london.vg.json +++ b/examples/compiled/geo_layer_line_london.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 700, "height": 500, + "style": "view", "encode": {"update": {"stroke": {"value": "transparent"}}}, "data": [ { diff --git a/examples/compiled/geo_line.vg.json b/examples/compiled/geo_line.vg.json index ee3bcb803a6..6220f8efc72 100644 --- a/examples/compiled/geo_line.vg.json +++ b/examples/compiled/geo_line.vg.json @@ -5,6 +5,7 @@ "padding": 5, "width": 800, "height": 500, + "style": "view", "data": [ { "name": "source_0", diff --git a/examples/compiled/geo_params_projections.vg.json b/examples/compiled/geo_params_projections.vg.json index d8933df7023..03b8102be8f 100644 --- a/examples/compiled/geo_params_projections.vg.json +++ b/examples/compiled/geo_params_projections.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 500, "height": 300, + "style": "view", "data": [ { "name": "source_0", diff --git a/examples/compiled/geo_point.vg.json b/examples/compiled/geo_point.vg.json index 1ae2c7c5092..4991440538e 100644 --- a/examples/compiled/geo_point.vg.json +++ b/examples/compiled/geo_point.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 500, "height": 300, + "style": "view", "data": [ { "name": "source_0", diff --git a/examples/compiled/geo_repeat.vg.json b/examples/compiled/geo_repeat.vg.json index ab1e7626146..52b141ba781 100644 --- a/examples/compiled/geo_repeat.vg.json +++ b/examples/compiled/geo_repeat.vg.json @@ -101,6 +101,7 @@ { "type": "group", "name": "child__row_population_group", + "style": "view", "encode": { "update": { "width": {"signal": "width"}, @@ -145,6 +146,7 @@ { "type": "group", "name": "child__row_engineers_group", + "style": "view", "encode": { "update": { "width": {"signal": "width"}, @@ -189,6 +191,7 @@ { "type": "group", "name": "child__row_hurricanes_group", + "style": "view", "encode": { "update": { "width": {"signal": "width"}, diff --git a/examples/compiled/geo_rule.vg.json b/examples/compiled/geo_rule.vg.json index 3fbd119fab2..a1e005b3455 100644 --- a/examples/compiled/geo_rule.vg.json +++ b/examples/compiled/geo_rule.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 800, "height": 500, + "style": "view", "data": [ { "name": "source_0", diff --git a/examples/compiled/geo_sphere.vg.json b/examples/compiled/geo_sphere.vg.json index 1665877a97f..d1f0cc01891 100644 --- a/examples/compiled/geo_sphere.vg.json +++ b/examples/compiled/geo_sphere.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 200, "height": 200, + "style": "view", "data": [ {"name": "source_0", "values": [{"type": "Sphere"}]}, {"name": "source_1", "transform": [{"type": "graticule"}]} diff --git a/examples/compiled/geo_text.vg.json b/examples/compiled/geo_text.vg.json index fdf4712a9d1..070f566b959 100644 --- a/examples/compiled/geo_text.vg.json +++ b/examples/compiled/geo_text.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 800, "height": 500, + "style": "view", "data": [ { "name": "source_0", diff --git a/examples/compiled/geo_trellis.vg.json b/examples/compiled/geo_trellis.vg.json index 3da339cb3d6..23073cb4ae6 100644 --- a/examples/compiled/geo_trellis.vg.json +++ b/examples/compiled/geo_trellis.vg.json @@ -85,6 +85,7 @@ { "name": "cell", "type": "group", + "style": "view", "from": { "facet": {"name": "facet", "data": "source_0", "groupby": ["group"]} }, diff --git a/examples/compiled/interactive_1d_geo_brush.png b/examples/compiled/interactive_1d_geo_brush.png new file mode 100644 index 0000000000000000000000000000000000000000..17dfd8f159e752ed01c3553534de1419376624dd GIT binary patch literal 144635 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

DaoKKTdlMq^-N_gUCRT;%7)XteUm> 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

{npe6eVL!?(m?ED*l6F>V}3mv8Zfj)<>Hl*XnMa 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 literal 0 HcmV?d00001 diff --git a/examples/compiled/interactive_1d_geo_brush.svg b/examples/compiled/interactive_1d_geo_brush.svg new file mode 100644 index 00000000000..d7558f3c323 --- /dev/null +++ b/examples/compiled/interactive_1d_geo_brush.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/compiled/interactive_1d_geo_brush.vg.json b/examples/compiled/interactive_1d_geo_brush.vg.json new file mode 100644 index 00000000000..cc4abb825d9 --- /dev/null +++ b/examples/compiled/interactive_1d_geo_brush.vg.json @@ -0,0 +1,346 @@ +{ + "$schema": "https://vega.github.io/schema/vega/v5.json", + "background": "white", + "padding": 5, + "width": 500, + "height": 300, + "style": "view", + "data": [ + { + "name": "brush_store", + "transform": [{"type": "collect", "sort": {"field": "_vgsid_"}}], + "values": [{"unit": "layer_1", "_vgsid_": [45, 51.5]}] + }, + { + "name": "source_0", + "url": "data/us-10m.json", + "format": {"type": "topojson", "feature": "states"}, + "transform": [{"type": "identifier", "as": "_vgsid_"}] + }, + { + "name": "source_1", + "url": "data/airports.csv", + "format": {"type": "csv"}, + "transform": [ + {"type": "identifier", "as": "_vgsid_"}, + { + "type": "filter", + "expr": "datum.state !== 'PR' && datum.state !== 'VI'" + }, + { + "type": "geojson", + "fields": ["longitude", "latitude"], + "signal": "layer_1_geojson_0" + }, + { + "type": "geopoint", + "projection": "projection", + "fields": ["longitude", "latitude"], + "as": ["layer_1_x", "layer_1_y"] + } + ] + } + ], + "projections": [ + { + "name": "projection", + "size": {"signal": "[width, height]"}, + "fit": {"signal": "[data('source_0'), layer_1_geojson_0]"}, + "type": "albersUsa" + } + ], + "signals": [ + { + "name": "unit", + "value": {}, + "on": [ + {"events": "mousemove", "update": "isTuple(group()) ? group() : unit"} + ] + }, + { + "name": "geo_interval_init_tick", + "value": null, + "on": [ + { + "events": "timer{1}", + "update": "geo_interval_init_tick === null ? {} : geo_interval_init_tick" + } + ] + }, + { + "name": "brush", + "update": "vlSelectionResolve(\"brush_store\", \"union\")" + }, + { + "name": "projection_center", + "update": "invert(\"projection\", [width/2, height/2])" + }, + { + "name": "brush_init", + "init": "[scale(\"projection\", [projection_center[0], 45]), scale(\"projection\", [projection_center[0], 51.5])]" + }, + { + "name": "brush_latitude_1", + "init": "[brush_init[0][1], brush_init[1][1]]", + "on": [ + { + "events": { + "source": "scope", + "type": "mousedown", + "filter": [ + "!event.item || event.item.mark.name !== \"brush_brush\"" + ] + }, + "update": "[y(unit), y(unit)]" + }, + { + "events": { + "source": "window", + "type": "mousemove", + "consume": true, + "between": [ + { + "source": "scope", + "type": "mousedown", + "filter": [ + "!event.item || event.item.mark.name !== \"brush_brush\"" + ] + }, + {"source": "window", "type": "mouseup"} + ] + }, + "update": "[brush_latitude_1[0], clamp(y(unit), 0, height)]" + }, + { + "events": [{"source": "view", "type": "dblclick"}], + "update": "[0, 0]" + }, + { + "events": {"signal": "brush_translate_delta"}, + "update": "clampRange(panLinear(brush_translate_anchor.extent_y, brush_translate_delta.y / span(brush_translate_anchor.extent_y)), 0, height)" + }, + { + "events": {"signal": "brush_zoom_delta"}, + "update": "clampRange(zoomLinear(brush_latitude_1, brush_zoom_anchor.y, brush_zoom_delta), 0, height)" + } + ] + }, + { + "name": "brush_tuple", + "on": [ + { + "events": [ + {"signal": "brush_latitude_1"}, + {"signal": "geo_interval_init_tick"} + ], + "update": "vlSelectionTuples(intersect([[0, brush_latitude_1[0]],[width, brush_latitude_1[1]]], {markname: \"layer_1_marks\"}, unit.mark), {unit: \"layer_1\"})" + } + ] + }, + { + "name": "brush_translate_anchor", + "value": {}, + "on": [ + { + "events": [ + {"source": "scope", "type": "mousedown", "markname": "brush_brush"} + ], + "update": "{x: x(unit), y: y(unit), extent_y: slice(brush_latitude_1)}" + } + ] + }, + { + "name": "brush_translate_delta", + "value": {}, + "on": [ + { + "events": [ + { + "source": "window", + "type": "mousemove", + "consume": true, + "between": [ + { + "source": "scope", + "type": "mousedown", + "markname": "brush_brush" + }, + {"source": "window", "type": "mouseup"} + ] + } + ], + "update": "{x: brush_translate_anchor.x - x(unit), y: brush_translate_anchor.y - y(unit)}" + } + ] + }, + { + "name": "brush_zoom_anchor", + "on": [ + { + "events": [ + { + "source": "scope", + "type": "wheel", + "consume": true, + "markname": "brush_brush" + } + ], + "update": "{x: x(unit), y: y(unit)}" + } + ] + }, + { + "name": "brush_zoom_delta", + "on": [ + { + "events": [ + { + "source": "scope", + "type": "wheel", + "consume": true, + "markname": "brush_brush" + } + ], + "force": true, + "update": "pow(1.001, event.deltaY * pow(16, event.deltaMode))" + } + ] + }, + { + "name": "brush_modify", + "on": [ + { + "events": {"signal": "brush_tuple"}, + "update": "modify(\"brush_store\", brush_tuple, true)" + } + ] + } + ], + "marks": [ + { + "name": "brush_brush_bg", + "type": "rect", + "clip": true, + "encode": { + "enter": {"fill": {"value": "#333"}, "fillOpacity": {"value": 0.125}}, + "update": { + "x": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"layer_1\"", + "value": 0 + }, + {"value": 0} + ], + "y": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"layer_1\"", + "signal": "brush_latitude_1[0]" + }, + {"value": 0} + ], + "x2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"layer_1\"", + "field": {"group": "width"} + }, + {"value": 0} + ], + "y2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"layer_1\"", + "signal": "brush_latitude_1[1]" + }, + {"value": 0} + ] + } + } + }, + { + "name": "layer_0_marks", + "type": "shape", + "style": ["geoshape"], + "interactive": true, + "from": {"data": "source_0"}, + "encode": { + "update": { + "fill": {"value": "lightgray"}, + "stroke": {"value": "white"}, + "ariaRoleDescription": {"value": "geoshape"} + } + }, + "transform": [{"type": "geoshape", "projection": "projection"}] + }, + { + "name": "layer_1_marks", + "type": "symbol", + "style": ["circle"], + "interactive": true, + "from": {"data": "source_1"}, + "encode": { + "update": { + "opacity": {"value": 0.7}, + "fill": [ + { + "test": "length(data(\"brush_store\")) && vlSelectionIdTest(\"brush_store\", datum)", + "value": "goldenrod" + }, + {"value": "steelblue"} + ], + "ariaRoleDescription": {"value": "circle"}, + "description": { + "signal": "\"longitude: \" + (format(datum[\"longitude\"], \"\")) + \"; latitude: \" + (format(datum[\"latitude\"], \"\"))" + }, + "x": {"field": "layer_1_x"}, + "y": {"field": "layer_1_y"}, + "size": {"value": 10}, + "shape": {"value": "circle"} + } + } + }, + { + "name": "brush_brush", + "type": "rect", + "clip": true, + "encode": { + "enter": {"fill": {"value": "transparent"}}, + "update": { + "x": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"layer_1\"", + "value": 0 + }, + {"value": 0} + ], + "y": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"layer_1\"", + "signal": "brush_latitude_1[0]" + }, + {"value": 0} + ], + "x2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"layer_1\"", + "field": {"group": "width"} + }, + {"value": 0} + ], + "y2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"layer_1\"", + "signal": "brush_latitude_1[1]" + }, + {"value": 0} + ], + "stroke": [ + { + "test": "brush_latitude_1[0] !== brush_latitude_1[1]", + "value": "white" + }, + {"value": null} + ] + } + } + } + ] +} diff --git a/examples/compiled/interactive_airport_crossfilter.png b/examples/compiled/interactive_airport_crossfilter.png new file mode 100644 index 0000000000000000000000000000000000000000..416f6efead8ff4933952b9e1abed882464850347 GIT binary patch literal 76040 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 Td&LR`!EZ%qxTs|5_xt_^VS$C& literal 0 HcmV?d00001 diff --git a/examples/compiled/interactive_airport_crossfilter.svg b/examples/compiled/interactive_airport_crossfilter.svg new file mode 100644 index 00000000000..216bb5f98b5 --- /dev/null +++ b/examples/compiled/interactive_airport_crossfilter.svg @@ -0,0 +1 @@ +02004006008001,0001,2001,4001,6001,8002,0002,2002,400distance (binned)02004006008001,000Count of Records−40−20020406080100120140160180200220240260delay (binned)0200400600800Count of Records \ No newline at end of file diff --git a/examples/compiled/interactive_airport_crossfilter.vg.json b/examples/compiled/interactive_airport_crossfilter.vg.json new file mode 100644 index 00000000000..a5840d10777 --- /dev/null +++ b/examples/compiled/interactive_airport_crossfilter.vg.json @@ -0,0 +1,841 @@ +{ + "$schema": "https://vega.github.io/schema/vega/v5.json", + "background": "white", + "padding": 5, + "data": [ + { + "name": "brush_store", + "transform": [{"type": "collect", "sort": {"field": "_vgsid_"}}], + "values": [{"unit": "concat_0_layer_1", "_vgsid_": [30, 40]}] + }, + {"name": "source_2", "url": "data/airports.csv", "format": {"type": "csv"}}, + { + "name": "source_0", + "url": "data/us-10m.json", + "format": {"type": "topojson", "feature": "states"}, + "transform": [{"type": "identifier", "as": "_vgsid_"}] + }, + { + "name": "source_1", + "url": "data/flights-airport.csv", + "format": {"type": "csv"}, + "transform": [ + {"type": "identifier", "as": "_vgsid_"}, + { + "type": "aggregate", + "groupby": ["origin"], + "ops": ["count"], + "fields": [null], + "as": ["routes"] + }, + {"type": "identifier", "as": "_vgsid_"}, + { + "type": "lookup", + "from": "source_2", + "key": "iata", + "fields": ["origin"], + "values": ["state", "latitude", "longitude"] + }, + { + "type": "filter", + "expr": "datum.state !== 'PR' && datum.state !== 'VI'" + }, + { + "type": "geojson", + "fields": ["longitude", "latitude"], + "signal": "concat_0_layer_1_geojson_0" + }, + { + "type": "geopoint", + "projection": "projection", + "fields": ["longitude", "latitude"], + "as": ["concat_0_layer_1_x", "concat_0_layer_1_y"] + }, + { + "type": "filter", + "expr": "isValid(datum[\"routes\"]) && isFinite(+datum[\"routes\"])" + } + ] + }, + { + "name": "data_0", + "source": "source_1", + "transform": [ + { + "type": "filter", + "expr": "!length(data(\"brush_store\")) || vlSelectionIdTest(\"brush_store\", datum)" + } + ] + }, + { + "name": "source_3", + "url": "data/flights-2k.json", + "format": {"type": "json", "parse": {"date": "date"}}, + "transform": [ + {"type": "identifier", "as": "_vgsid_"}, + { + "type": "extent", + "field": "delay", + "signal": "child__column_delay_layer_1_bin_maxbins_20_delay_extent" + }, + { + "type": "bin", + "field": "delay", + "as": ["bin_maxbins_20_delay", "bin_maxbins_20_delay_end"], + "signal": "child__column_delay_layer_1_bin_maxbins_20_delay_bins", + "extent": { + "signal": "child__column_delay_layer_1_bin_maxbins_20_delay_extent" + }, + "maxbins": 20 + }, + { + "type": "extent", + "field": "distance", + "signal": "child__column_distance_layer_0_bin_maxbins_20_distance_extent" + }, + { + "type": "bin", + "field": "distance", + "as": ["bin_maxbins_20_distance", "bin_maxbins_20_distance_end"], + "signal": "child__column_distance_layer_0_bin_maxbins_20_distance_bins", + "extent": { + "signal": "child__column_distance_layer_0_bin_maxbins_20_distance_extent" + }, + "maxbins": 20 + }, + { + "type": "lookup", + "from": "data_0", + "key": "origin", + "fields": ["origin"], + "as": ["brush"] + } + ] + }, + { + "name": "data_1", + "source": "source_3", + "transform": [ + { + "type": "filter", + "expr": "data('brush_store').length && isValid(datum.brush)" + } + ] + }, + { + "name": "data_2", + "source": "data_1", + "transform": [ + { + "type": "aggregate", + "groupby": ["bin_maxbins_20_delay", "bin_maxbins_20_delay_end"], + "ops": ["count"], + "fields": [null], + "as": ["__count"] + }, + { + "type": "filter", + "expr": "isValid(datum[\"bin_maxbins_20_delay\"]) && isFinite(+datum[\"bin_maxbins_20_delay\"])" + } + ] + }, + { + "name": "data_3", + "source": "data_1", + "transform": [ + { + "type": "aggregate", + "groupby": ["bin_maxbins_20_distance", "bin_maxbins_20_distance_end"], + "ops": ["count"], + "fields": [null], + "as": ["__count"] + }, + { + "type": "filter", + "expr": "isValid(datum[\"bin_maxbins_20_distance\"]) && isFinite(+datum[\"bin_maxbins_20_distance\"])" + } + ] + }, + { + "name": "data_4", + "source": "source_3", + "transform": [ + { + "type": "aggregate", + "groupby": ["bin_maxbins_20_distance", "bin_maxbins_20_distance_end"], + "ops": ["count"], + "fields": [null], + "as": ["__count"] + }, + { + "type": "filter", + "expr": "isValid(datum[\"bin_maxbins_20_distance\"]) && isFinite(+datum[\"bin_maxbins_20_distance\"])" + } + ] + }, + { + "name": "data_5", + "source": "source_3", + "transform": [ + { + "type": "aggregate", + "groupby": ["bin_maxbins_20_delay", "bin_maxbins_20_delay_end"], + "ops": ["count"], + "fields": [null], + "as": ["__count"] + }, + { + "type": "filter", + "expr": "isValid(datum[\"bin_maxbins_20_delay\"]) && isFinite(+datum[\"bin_maxbins_20_delay\"])" + } + ] + } + ], + "projections": [ + { + "name": "projection", + "size": {"signal": "[concat_0_width, concat_0_height]"}, + "fit": {"signal": "[data('source_0'), concat_0_layer_1_geojson_0]"}, + "type": "albersUsa" + } + ], + "signals": [ + {"name": "concat_0_width", "value": 500}, + {"name": "concat_0_height", "value": 300}, + {"name": "concat_1_childWidth", "value": 200}, + {"name": "concat_1_childHeight", "value": 200}, + { + "name": "unit", + "value": {}, + "on": [ + {"events": "mousemove", "update": "isTuple(group()) ? group() : unit"} + ] + }, + { + "name": "geo_interval_init_tick", + "value": null, + "on": [ + { + "events": "timer{1}", + "update": "geo_interval_init_tick === null ? {} : geo_interval_init_tick" + } + ] + }, + { + "name": "brush", + "update": "vlSelectionResolve(\"brush_store\", \"union\")" + } + ], + "layout": {"padding": 20, "columns": 1, "bounds": "full", "align": "each"}, + "marks": [ + { + "type": "group", + "name": "concat_0_group", + "style": "view", + "encode": { + "update": { + "width": {"signal": "concat_0_width"}, + "height": {"signal": "concat_0_height"} + } + }, + "signals": [ + { + "name": "brush_init", + "init": "[scale(\"projection\", [-86, 30]), scale(\"projection\", [-118, 40])]" + }, + { + "name": "brush_latitude_1", + "init": "[brush_init[0][1], brush_init[1][1]]", + "on": [ + { + "events": { + "source": "scope", + "type": "mousedown", + "filter": [ + "!event.item || event.item.mark.name !== \"brush_brush\"" + ] + }, + "update": "[y(unit), y(unit)]" + }, + { + "events": { + "source": "window", + "type": "mousemove", + "consume": true, + "between": [ + { + "source": "scope", + "type": "mousedown", + "filter": [ + "!event.item || event.item.mark.name !== \"brush_brush\"" + ] + }, + {"source": "window", "type": "mouseup"} + ] + }, + "update": "[brush_latitude_1[0], clamp(y(unit), 0, concat_0_height)]" + }, + { + "events": [{"source": "view", "type": "dblclick"}], + "update": "[0, 0]" + }, + { + "events": {"signal": "brush_translate_delta"}, + "update": "clampRange(panLinear(brush_translate_anchor.extent_y, brush_translate_delta.y / span(brush_translate_anchor.extent_y)), 0, concat_0_height)" + }, + { + "events": {"signal": "brush_zoom_delta"}, + "update": "clampRange(zoomLinear(brush_latitude_1, brush_zoom_anchor.y, brush_zoom_delta), 0, concat_0_height)" + } + ] + }, + { + "name": "brush_longitude_1", + "init": "[brush_init[0][0], brush_init[1][0]]", + "on": [ + { + "events": { + "source": "scope", + "type": "mousedown", + "filter": [ + "!event.item || event.item.mark.name !== \"brush_brush\"" + ] + }, + "update": "[x(unit), x(unit)]" + }, + { + "events": { + "source": "window", + "type": "mousemove", + "consume": true, + "between": [ + { + "source": "scope", + "type": "mousedown", + "filter": [ + "!event.item || event.item.mark.name !== \"brush_brush\"" + ] + }, + {"source": "window", "type": "mouseup"} + ] + }, + "update": "[brush_longitude_1[0], clamp(x(unit), 0, concat_0_width)]" + }, + { + "events": [{"source": "view", "type": "dblclick"}], + "update": "[0, 0]" + }, + { + "events": {"signal": "brush_translate_delta"}, + "update": "clampRange(panLinear(brush_translate_anchor.extent_x, brush_translate_delta.x / span(brush_translate_anchor.extent_x)), 0, concat_0_width)" + }, + { + "events": {"signal": "brush_zoom_delta"}, + "update": "clampRange(zoomLinear(brush_longitude_1, brush_zoom_anchor.x, brush_zoom_delta), 0, concat_0_width)" + } + ] + }, + { + "name": "brush_tuple", + "on": [ + { + "events": [ + {"signal": "brush_latitude_1 || brush_longitude_1"}, + {"signal": "geo_interval_init_tick"} + ], + "update": "vlSelectionTuples(intersect([[brush_longitude_1[0], brush_latitude_1[0]],[brush_longitude_1[1], brush_latitude_1[1]]], {markname: \"concat_0_layer_1_marks\"}, unit.mark), {unit: \"concat_0_layer_1\"})" + } + ] + }, + { + "name": "brush_translate_anchor", + "value": {}, + "on": [ + { + "events": [ + { + "source": "scope", + "type": "mousedown", + "markname": "brush_brush" + } + ], + "update": "{x: x(unit), y: y(unit), extent_x: slice(brush_longitude_1), extent_y: slice(brush_latitude_1)}" + } + ] + }, + { + "name": "brush_translate_delta", + "value": {}, + "on": [ + { + "events": [ + { + "source": "window", + "type": "mousemove", + "consume": true, + "between": [ + { + "source": "scope", + "type": "mousedown", + "markname": "brush_brush" + }, + {"source": "window", "type": "mouseup"} + ] + } + ], + "update": "{x: brush_translate_anchor.x - x(unit), y: brush_translate_anchor.y - y(unit)}" + } + ] + }, + { + "name": "brush_zoom_anchor", + "on": [ + { + "events": [ + { + "source": "scope", + "type": "wheel", + "consume": true, + "markname": "brush_brush" + } + ], + "update": "{x: x(unit), y: y(unit)}" + } + ] + }, + { + "name": "brush_zoom_delta", + "on": [ + { + "events": [ + { + "source": "scope", + "type": "wheel", + "consume": true, + "markname": "brush_brush" + } + ], + "force": true, + "update": "pow(1.001, event.deltaY * pow(16, event.deltaMode))" + } + ] + }, + { + "name": "brush_modify", + "on": [ + { + "events": {"signal": "brush_tuple"}, + "update": "modify(\"brush_store\", brush_tuple, true)" + } + ] + } + ], + "marks": [ + { + "name": "brush_brush_bg", + "type": "rect", + "clip": true, + "encode": { + "enter": { + "fill": {"value": "#333"}, + "fillOpacity": {"value": 0.125} + }, + "update": { + "x": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"concat_0_layer_1\"", + "signal": "brush_longitude_1[0]" + }, + {"value": 0} + ], + "y": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"concat_0_layer_1\"", + "signal": "brush_latitude_1[0]" + }, + {"value": 0} + ], + "x2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"concat_0_layer_1\"", + "signal": "brush_longitude_1[1]" + }, + {"value": 0} + ], + "y2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"concat_0_layer_1\"", + "signal": "brush_latitude_1[1]" + }, + {"value": 0} + ] + } + } + }, + { + "name": "concat_0_layer_0_marks", + "type": "shape", + "style": ["geoshape"], + "interactive": true, + "from": {"data": "source_0"}, + "encode": { + "update": { + "fill": {"value": "lightgray"}, + "stroke": {"value": "white"}, + "ariaRoleDescription": {"value": "geoshape"} + } + }, + "transform": [{"type": "geoshape", "projection": "projection"}] + }, + { + "name": "concat_0_layer_1_marks", + "type": "symbol", + "style": ["circle"], + "interactive": true, + "from": {"data": "source_1"}, + "encode": { + "update": { + "opacity": {"value": 0.7}, + "fill": [ + { + "test": "length(data(\"brush_store\")) && vlSelectionIdTest(\"brush_store\", datum)", + "value": "goldenrod" + }, + {"value": "steelblue"} + ], + "ariaRoleDescription": {"value": "circle"}, + "description": { + "signal": "\"longitude: \" + (format(datum[\"longitude\"], \"\")) + \"; latitude: \" + (format(datum[\"latitude\"], \"\")) + \"; routes: \" + (format(datum[\"routes\"], \"\"))" + }, + "x": {"field": "concat_0_layer_1_x"}, + "y": {"field": "concat_0_layer_1_y"}, + "size": {"scale": "size", "field": "routes"}, + "shape": {"value": "circle"} + } + } + }, + { + "name": "brush_brush", + "type": "rect", + "clip": true, + "encode": { + "enter": {"fill": {"value": "transparent"}}, + "update": { + "x": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"concat_0_layer_1\"", + "signal": "brush_longitude_1[0]" + }, + {"value": 0} + ], + "y": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"concat_0_layer_1\"", + "signal": "brush_latitude_1[0]" + }, + {"value": 0} + ], + "x2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"concat_0_layer_1\"", + "signal": "brush_longitude_1[1]" + }, + {"value": 0} + ], + "y2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"concat_0_layer_1\"", + "signal": "brush_latitude_1[1]" + }, + {"value": 0} + ], + "stroke": [ + { + "test": "brush_longitude_1[0] !== brush_longitude_1[1] && brush_latitude_1[0] !== brush_latitude_1[1]", + "value": "white" + }, + {"value": null} + ] + } + } + } + ] + }, + { + "type": "group", + "name": "concat_1_group", + "layout": {"padding": 20, "columns": 2, "bounds": "full", "align": "all"}, + "marks": [ + { + "type": "group", + "name": "child__column_distance_group", + "style": "cell", + "encode": { + "update": { + "width": {"signal": "concat_1_childWidth"}, + "height": {"signal": "concat_1_childHeight"} + } + }, + "marks": [ + { + "name": "child__column_distance_layer_0_marks", + "type": "rect", + "style": ["bar"], + "interactive": false, + "from": {"data": "data_4"}, + "encode": { + "update": { + "fill": {"value": "steelblue"}, + "ariaRoleDescription": {"value": "bar"}, + "description": { + "signal": "\"distance (binned): \" + (!isValid(datum[\"bin_maxbins_20_distance\"]) || !isFinite(+datum[\"bin_maxbins_20_distance\"]) ? \"null\" : format(datum[\"bin_maxbins_20_distance\"], \"\") + \" – \" + format(datum[\"bin_maxbins_20_distance_end\"], \"\")) + \"; Count of Records: \" + (format(datum[\"__count\"], \"\"))" + }, + "x2": { + "scale": "child__column_distance_x", + "field": "bin_maxbins_20_distance", + "offset": 1 + }, + "x": { + "scale": "child__column_distance_x", + "field": "bin_maxbins_20_distance_end" + }, + "y": { + "scale": "child__column_distance_y", + "field": "__count" + }, + "y2": {"scale": "child__column_distance_y", "value": 0} + } + } + }, + { + "name": "child__column_distance_layer_1_marks", + "type": "rect", + "style": ["bar"], + "interactive": false, + "from": {"data": "data_3"}, + "encode": { + "update": { + "fill": {"value": "goldenrod"}, + "ariaRoleDescription": {"value": "bar"}, + "description": { + "signal": "\"distance (binned): \" + (!isValid(datum[\"bin_maxbins_20_distance\"]) || !isFinite(+datum[\"bin_maxbins_20_distance\"]) ? \"null\" : format(datum[\"bin_maxbins_20_distance\"], \"\") + \" – \" + format(datum[\"bin_maxbins_20_distance_end\"], \"\")) + \"; Count of Records: \" + (format(datum[\"__count\"], \"\"))" + }, + "x2": { + "scale": "child__column_distance_x", + "field": "bin_maxbins_20_distance", + "offset": 1 + }, + "x": { + "scale": "child__column_distance_x", + "field": "bin_maxbins_20_distance_end" + }, + "y": { + "scale": "child__column_distance_y", + "field": "__count" + }, + "y2": {"scale": "child__column_distance_y", "value": 0} + } + } + } + ], + "axes": [ + { + "scale": "child__column_distance_y", + "orient": "left", + "gridScale": "child__column_distance_x", + "grid": true, + "tickCount": {"signal": "ceil(concat_1_childHeight/40)"}, + "domain": false, + "labels": false, + "aria": false, + "maxExtent": 0, + "minExtent": 0, + "ticks": false, + "zindex": 0 + }, + { + "scale": "child__column_distance_x", + "orient": "bottom", + "grid": false, + "title": "distance (binned)", + "labelFlush": true, + "labelOverlap": true, + "tickCount": {"signal": "ceil(concat_1_childWidth/10)"}, + "zindex": 0 + }, + { + "scale": "child__column_distance_y", + "orient": "left", + "grid": false, + "title": "Count of Records", + "labelOverlap": true, + "tickCount": {"signal": "ceil(concat_1_childHeight/40)"}, + "zindex": 0 + } + ] + }, + { + "type": "group", + "name": "child__column_delay_group", + "style": "cell", + "encode": { + "update": { + "width": {"signal": "concat_1_childWidth"}, + "height": {"signal": "concat_1_childHeight"} + } + }, + "marks": [ + { + "name": "child__column_delay_layer_0_marks", + "type": "rect", + "style": ["bar"], + "interactive": false, + "from": {"data": "data_5"}, + "encode": { + "update": { + "fill": {"value": "steelblue"}, + "ariaRoleDescription": {"value": "bar"}, + "description": { + "signal": "\"delay (binned): \" + (!isValid(datum[\"bin_maxbins_20_delay\"]) || !isFinite(+datum[\"bin_maxbins_20_delay\"]) ? \"null\" : format(datum[\"bin_maxbins_20_delay\"], \"\") + \" – \" + format(datum[\"bin_maxbins_20_delay_end\"], \"\")) + \"; Count of Records: \" + (format(datum[\"__count\"], \"\"))" + }, + "x2": { + "scale": "child__column_delay_x", + "field": "bin_maxbins_20_delay", + "offset": 1 + }, + "x": { + "scale": "child__column_delay_x", + "field": "bin_maxbins_20_delay_end" + }, + "y": {"scale": "child__column_delay_y", "field": "__count"}, + "y2": {"scale": "child__column_delay_y", "value": 0} + } + } + }, + { + "name": "child__column_delay_layer_1_marks", + "type": "rect", + "style": ["bar"], + "interactive": false, + "from": {"data": "data_2"}, + "encode": { + "update": { + "fill": {"value": "goldenrod"}, + "ariaRoleDescription": {"value": "bar"}, + "description": { + "signal": "\"delay (binned): \" + (!isValid(datum[\"bin_maxbins_20_delay\"]) || !isFinite(+datum[\"bin_maxbins_20_delay\"]) ? \"null\" : format(datum[\"bin_maxbins_20_delay\"], \"\") + \" – \" + format(datum[\"bin_maxbins_20_delay_end\"], \"\")) + \"; Count of Records: \" + (format(datum[\"__count\"], \"\"))" + }, + "x2": { + "scale": "child__column_delay_x", + "field": "bin_maxbins_20_delay", + "offset": 1 + }, + "x": { + "scale": "child__column_delay_x", + "field": "bin_maxbins_20_delay_end" + }, + "y": {"scale": "child__column_delay_y", "field": "__count"}, + "y2": {"scale": "child__column_delay_y", "value": 0} + } + } + } + ], + "axes": [ + { + "scale": "child__column_delay_y", + "orient": "left", + "gridScale": "child__column_delay_x", + "grid": true, + "tickCount": {"signal": "ceil(concat_1_childHeight/40)"}, + "domain": false, + "labels": false, + "aria": false, + "maxExtent": 0, + "minExtent": 0, + "ticks": false, + "zindex": 0 + }, + { + "scale": "child__column_delay_x", + "orient": "bottom", + "grid": false, + "title": "delay (binned)", + "labelFlush": true, + "labelOverlap": true, + "tickCount": {"signal": "ceil(concat_1_childWidth/10)"}, + "zindex": 0 + }, + { + "scale": "child__column_delay_y", + "orient": "left", + "grid": false, + "title": "Count of Records", + "labelOverlap": true, + "tickCount": {"signal": "ceil(concat_1_childHeight/40)"}, + "zindex": 0 + } + ] + } + ] + } + ], + "scales": [ + { + "name": "size", + "type": "linear", + "domain": {"data": "source_1", "field": "routes"}, + "range": [0, 500], + "zero": true + }, + { + "name": "child__column_distance_x", + "type": "linear", + "domain": { + "signal": "[child__column_distance_layer_0_bin_maxbins_20_distance_bins.start, child__column_distance_layer_0_bin_maxbins_20_distance_bins.stop]" + }, + "range": [0, {"signal": "concat_1_childWidth"}], + "bins": { + "signal": "child__column_distance_layer_0_bin_maxbins_20_distance_bins" + }, + "zero": false + }, + { + "name": "child__column_distance_y", + "type": "linear", + "domain": { + "fields": [ + {"data": "data_4", "field": "__count"}, + {"data": "data_3", "field": "__count"} + ] + }, + "range": [{"signal": "concat_1_childHeight"}, 0], + "nice": true, + "zero": true + }, + { + "name": "child__column_delay_x", + "type": "linear", + "domain": { + "signal": "[child__column_delay_layer_1_bin_maxbins_20_delay_bins.start, child__column_delay_layer_1_bin_maxbins_20_delay_bins.stop]" + }, + "range": [0, {"signal": "concat_1_childWidth"}], + "bins": { + "signal": "child__column_delay_layer_1_bin_maxbins_20_delay_bins" + }, + "zero": false + }, + { + "name": "child__column_delay_y", + "type": "linear", + "domain": { + "fields": [ + {"data": "data_5", "field": "__count"}, + {"data": "data_2", "field": "__count"} + ] + }, + "range": [{"signal": "concat_1_childHeight"}, 0], + "nice": true, + "zero": true + } + ] +} diff --git a/examples/compiled/interactive_global_development.vg.json b/examples/compiled/interactive_global_development.vg.json index ac5f7564dbb..4e5bb816f3d 100644 --- a/examples/compiled/interactive_global_development.vg.json +++ b/examples/compiled/interactive_global_development.vg.json @@ -5,7 +5,7 @@ "padding": 5, "width": 800, "height": 500, - "style": "cell", + "style": ["view", "cell"], "data": [ { "name": "year_store", diff --git a/examples/compiled/layer_arc_label.vg.json b/examples/compiled/layer_arc_label.vg.json index 4605a566048..558ba6bfe2b 100644 --- a/examples/compiled/layer_arc_label.vg.json +++ b/examples/compiled/layer_arc_label.vg.json @@ -5,6 +5,7 @@ "padding": 5, "width": 200, "height": 200, + "style": "view", "data": [ { "name": "source_0", diff --git a/examples/compiled/layer_point_line_regression.vg.json b/examples/compiled/layer_point_line_regression.vg.json index 3821e0a01e7..1343f87402c 100644 --- a/examples/compiled/layer_point_line_regression.vg.json +++ b/examples/compiled/layer_point_line_regression.vg.json @@ -4,7 +4,7 @@ "padding": 5, "width": 200, "height": 200, - "style": "cell", + "style": ["cell", "view"], "data": [ {"name": "source_0", "url": "data/movies.json", "format": {"type": "json"}}, { diff --git a/examples/compiled/point_angle_windvector.vg.json b/examples/compiled/point_angle_windvector.vg.json index 176d380288e..5719b2b98b8 100644 --- a/examples/compiled/point_angle_windvector.vg.json +++ b/examples/compiled/point_angle_windvector.vg.json @@ -5,6 +5,7 @@ "padding": 5, "width": 615, "height": 560, + "style": "view", "data": [ { "name": "source_0", diff --git a/examples/compiled/point_overlap.vg.json b/examples/compiled/point_overlap.vg.json index 690003f29a0..3097b82c0a9 100644 --- a/examples/compiled/point_overlap.vg.json +++ b/examples/compiled/point_overlap.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 20, "height": 20, + "style": "view", "data": [ { "name": "source_0", diff --git a/examples/compiled/test_single_point_color.vg.json b/examples/compiled/test_single_point_color.vg.json index 45956b336df..daba5681875 100644 --- a/examples/compiled/test_single_point_color.vg.json +++ b/examples/compiled/test_single_point_color.vg.json @@ -4,6 +4,7 @@ "padding": 5, "width": 20, "height": 20, + "style": "view", "data": [{"name": "source_0", "values": [{"a": 2}]}], "marks": [ { diff --git a/examples/specs/interactive_1d_geo_brush.vl.json b/examples/specs/interactive_1d_geo_brush.vl.json new file mode 100644 index 00000000000..d9fad3c1151 --- /dev/null +++ b/examples/specs/interactive_1d_geo_brush.vl.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://vega.github.io/schema/vega-lite/v5.json", + "width": 500, + "height": 300, + "projection": {"type": "albersUsa"}, + "layer": [ + { + "data": { + "url": "data/us-10m.json", + "format": {"type": "topojson", "feature": "states"} + }, + "mark": {"type": "geoshape", "fill": "lightgray", "stroke": "white"} + }, + { + "data": {"url": "data/airports.csv"}, + "transform": [ + {"filter": "datum.state !== 'PR' && datum.state !== 'VI'"} + ], + "params": [ + { + "name": "brush", + "select": {"type": "interval", "encodings": ["latitude"]}, + "value": {"latitude": [45, 51.5]} + } + ], + "mark": "circle", + "encoding": { + "longitude": {"field": "longitude", "type": "quantitative"}, + "latitude": {"field": "latitude", "type": "quantitative"}, + "color": { + "condition": {"param": "brush", "empty": false, "value": "goldenrod"}, + "value": "steelblue" + }, + "size": {"value": 10} + } + } + ] +} diff --git a/examples/specs/interactive_airport_crossfilter.vl.json b/examples/specs/interactive_airport_crossfilter.vl.json new file mode 100644 index 00000000000..fc2164b9d13 --- /dev/null +++ b/examples/specs/interactive_airport_crossfilter.vl.json @@ -0,0 +1,115 @@ +{ + "$schema": "https://vega.github.io/schema/vega-lite/v5.json", + "vconcat": [ + { + "width": 500, + "height": 300, + "projection": { + "type": "albersUsa" + }, + "layer": [ + { + "data": { + "url": "data/us-10m.json", + "format": { + "type": "topojson", + "feature": "states" + } + }, + "mark": { + "type": "geoshape", + "fill": "lightgray", + "stroke": "white" + } + }, + { + "data": {"url": "data/flights-airport.csv"}, + "transform": [ + {"aggregate": [{"op": "count", "as": "routes"}], "groupby": ["origin"]}, + { + "lookup": "origin", + "from": { + "data": {"url": "data/airports.csv"}, + "key": "iata", + "fields": ["state", "latitude", "longitude"] + } + }, + {"filter": "datum.state !== 'PR' && datum.state !== 'VI'"} + ], + "params": [ + { + "name": "brush", + "select": "interval", + "value": {"latitude": [30, 40], "longitude": [-86, -118]} + } + ], + "mark": "circle", + "encoding": { + "longitude": { + "field": "longitude", + "type": "quantitative" + }, + "latitude": { + "field": "latitude", + "type": "quantitative" + }, + "size": { + "field": "routes", + "type": "quantitative", + "scale": {"rangeMax": 500}, + "legend": null + }, + "color": { + "condition": { + "param": "brush", "empty": false, + "value": "goldenrod" + }, + "value": "steelblue"} + } + } + ] + }, + { + "data": { + "url": "data/flights-2k.json", + "format": {"parse": {"date": "date"}} + }, + "transform": [ + { + "lookup": "origin", + "from": {"param": "brush", "key": "origin"} + } + ], + "repeat": {"column": ["distance", "delay"]}, + "spec": { + "layer": [ + { + "mark": "bar", + "encoding": { + "x": { + "field": {"repeat": "column"}, + "bin": {"maxbins": 20} + }, + "y": {"aggregate": "count"}, + "color": {"value": "steelblue"} + } + }, + { + "transform": [{ + "filter": "data('brush_store').length && isValid(datum.brush)" + }], + "mark": "bar", + "encoding": { + "x": { + "field": {"repeat": "column"}, + "bin": {"maxbins": 20} + }, + "y": {"aggregate": "count"}, + "color": {"value": "goldenrod"} + } + } + ] + } + } + ] +} diff --git a/examples/specs/normalized/interactive_1d_geo_brush_normalized.vl.json b/examples/specs/normalized/interactive_1d_geo_brush_normalized.vl.json new file mode 100644 index 00000000000..fce30944c71 --- /dev/null +++ b/examples/specs/normalized/interactive_1d_geo_brush_normalized.vl.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://vega.github.io/schema/vega-lite/v5.json", + "width": 500, + "height": 300, + "layer": [ + { + "data": { + "url": "data/us-10m.json", + "format": {"type": "topojson", "feature": "states"} + }, + "mark": {"type": "geoshape", "fill": "lightgray", "stroke": "white"}, + "projection": {"type": "albersUsa"} + }, + { + "data": {"url": "data/airports.csv"}, + "params": [ + { + "name": "brush", + "select": {"type": "interval", "encodings": ["latitude"]}, + "value": {"latitude": [45, 51.5]} + } + ], + "mark": "circle", + "encoding": { + "longitude": {"field": "longitude", "type": "quantitative"}, + "latitude": {"field": "latitude", "type": "quantitative"}, + "color": { + "condition": {"param": "brush", "empty": false, "value": "goldenrod"}, + "value": "steelblue" + }, + "size": {"value": 10} + }, + "transform": [{"filter": "datum.state !== 'PR' && datum.state !== 'VI'"}], + "projection": {"type": "albersUsa"} + } + ] +} \ No newline at end of file diff --git a/examples/specs/normalized/interactive_airport_crossfilter_normalized.vl.json b/examples/specs/normalized/interactive_airport_crossfilter_normalized.vl.json new file mode 100644 index 00000000000..796b0de4513 --- /dev/null +++ b/examples/specs/normalized/interactive_airport_crossfilter_normalized.vl.json @@ -0,0 +1,125 @@ +{ + "$schema": "https://vega.github.io/schema/vega-lite/v5.json", + "vconcat": [ + { + "width": 500, + "height": 300, + "layer": [ + { + "data": { + "url": "data/us-10m.json", + "format": {"type": "topojson", "feature": "states"} + }, + "mark": {"type": "geoshape", "fill": "lightgray", "stroke": "white"}, + "projection": {"type": "albersUsa"} + }, + { + "data": {"url": "data/flights-airport.csv"}, + "params": [ + { + "name": "brush", + "select": "interval", + "value": {"latitude": [30, 40], "longitude": [-86, -118]} + } + ], + "mark": "circle", + "encoding": { + "longitude": {"field": "longitude", "type": "quantitative"}, + "latitude": {"field": "latitude", "type": "quantitative"}, + "size": { + "field": "routes", + "type": "quantitative", + "scale": {"rangeMax": 500}, + "legend": null + }, + "color": { + "condition": { + "param": "brush", + "empty": false, + "value": "goldenrod" + }, + "value": "steelblue" + } + }, + "transform": [ + { + "aggregate": [{"op": "count", "as": "routes"}], + "groupby": ["origin"] + }, + { + "lookup": "origin", + "from": { + "data": {"url": "data/airports.csv"}, + "key": "iata", + "fields": ["state", "latitude", "longitude"] + } + }, + {"filter": "datum.state !== 'PR' && datum.state !== 'VI'"} + ], + "projection": {"type": "albersUsa"} + } + ] + }, + { + "data": { + "url": "data/flights-2k.json", + "format": {"parse": {"date": "date"}} + }, + "align": "all", + "transform": [ + {"lookup": "origin", "from": {"param": "brush", "key": "origin"}} + ], + "columns": 2, + "concat": [ + { + "layer": [ + { + "mark": "bar", + "encoding": { + "x": {"field": "distance", "bin": {"maxbins": 20}}, + "y": {"aggregate": "count"}, + "color": {"value": "steelblue"} + } + }, + { + "mark": "bar", + "encoding": { + "x": {"field": "distance", "bin": {"maxbins": 20}}, + "y": {"aggregate": "count"}, + "color": {"value": "goldenrod"} + }, + "transform": [ + {"filter": "data('brush_store').length && isValid(datum.brush)"} + ] + } + ], + "name": "child__column_distance" + }, + { + "layer": [ + { + "mark": "bar", + "encoding": { + "x": {"field": "delay", "bin": {"maxbins": 20}}, + "y": {"aggregate": "count"}, + "color": {"value": "steelblue"} + } + }, + { + "mark": "bar", + "encoding": { + "x": {"field": "delay", "bin": {"maxbins": 20}}, + "y": {"aggregate": "count"}, + "color": {"value": "goldenrod"} + }, + "transform": [ + {"filter": "data('brush_store').length && isValid(datum.brush)"} + ] + } + ], + "name": "child__column_delay" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/compile/mark/mark.ts b/src/compile/mark/mark.ts index 119d32eb8cc..009d9747534 100644 --- a/src/compile/mark/mark.ts +++ b/src/compile/mark/mark.ts @@ -376,7 +376,7 @@ function interactiveFlag(model: UnitModel) { } return parentCount ? { - interactive: unitCount > 0 || !!model.encoding.tooltip + interactive: unitCount > 0 || model.mark === 'geoshape' || !!model.encoding.tooltip } : null; } diff --git a/src/compile/selection/assemble.ts b/src/compile/selection/assemble.ts index e3069c47954..1b12eb3ee39 100644 --- a/src/compile/selection/assemble.ts +++ b/src/compile/selection/assemble.ts @@ -5,7 +5,7 @@ import {MODIFY, STORE, unitName, VL_SELECTION_RESOLVE, TUPLE, selectionCompilers import {dateTimeToExpr, isDateTime, dateTimeToTimestamp} from '../../datetime'; import {hasContinuousDomain} from '../../scale'; import {SelectionInit, SelectionInitInterval, ParameterExtent, SELECTION_ID} from '../../selection'; -import {keys, stringify, vals} from '../../util'; +import {keys, replacePathInField, stringify, vals} from '../../util'; import {VgData, VgDomain} from '../../vega.schema'; import {FacetModel} from '../facet'; import {LayerModel} from '../layer'; @@ -13,6 +13,13 @@ import {isUnitModel, Model} from '../model'; import {ScaleComponent} from '../scale/component'; import {UnitModel} from '../unit'; import {parseSelectionExtent} from './parse'; +import {SelectionProjection} from './project'; + +export function assembleProjection(proj: SelectionProjection) { + const {signals, hasLegend, index, ...rest} = proj; + rest.field = replacePathInField(rest.field); + return rest; +} export function assembleInit( init: readonly (SelectionInit | readonly SelectionInit[] | SelectionInitInterval)[] | SelectionInit, @@ -124,10 +131,7 @@ export function assembleUnitSelectionData(model: UnitModel, data: readonly VgDat } if (selCmpt.init) { - const fields = selCmpt.project.items.map(proj => { - const {signals, ...rest} = proj; - return rest; - }); + const fields = selCmpt.project.items.map(assembleProjection); store.values = selCmpt.project.hasSelectionId ? selCmpt.init.map(i => ({unit, [SELECTION_ID]: assembleInit(i, false)[0]})) diff --git a/src/compile/selection/index.ts b/src/compile/selection/index.ts index b6221ed3fb0..6f84162ed96 100644 --- a/src/compile/selection/index.ts +++ b/src/compile/selection/index.ts @@ -1,4 +1,4 @@ -import {Binding, isString, NewSignal, Signal, Stream} from 'vega'; +import {Binding, isString, Signal, Stream} from 'vega'; import {stringValue} from 'vega-util'; import {FACET_CHANNELS} from '../../channel'; import { @@ -45,8 +45,6 @@ export interface SelectionComponent { bind?: 'scales' | Binding | Dict | LegendBinding; resolve: SelectionResolution; mark?: BrushConfig; - - // Transforms project: SelectionProjectionComponent; scales?: SelectionProjection[]; toggle?: string; @@ -59,8 +57,8 @@ export interface SelectionComponent { export interface SelectionCompiler { defined: (selCmpt: SelectionComponent) => boolean; parse?: (model: UnitModel, selCmpt: SelectionComponent, def: SelectionParameter) => void; - signals?: (model: UnitModel, selCmpt: SelectionComponent, signals: NewSignal[]) => Signal[]; // the output can be a new or a push signal - topLevelSignals?: (model: Model, selCmpt: SelectionComponent, signals: NewSignal[]) => NewSignal[]; + signals?: (model: UnitModel, selCmpt: SelectionComponent, signals: Signal[]) => Signal[]; + topLevelSignals?: (model: Model, selCmpt: SelectionComponent, signals: Signal[]) => Signal[]; modifyExpr?: (model: UnitModel, selCmpt: SelectionComponent, expr: string) => string; marks?: (model: UnitModel, selCmpt: SelectionComponent, marks: any[]) => any[]; } diff --git a/src/compile/selection/inputs.ts b/src/compile/selection/inputs.ts index a434dc24e73..8e8e6c3afdb 100644 --- a/src/compile/selection/inputs.ts +++ b/src/compile/selection/inputs.ts @@ -6,6 +6,7 @@ import nearest from './nearest'; import {TUPLE_FIELDS} from './project'; import {SelectionCompiler} from '.'; import {isLegendBinding} from '../../selection'; +import {NewSignal} from 'vega'; const inputBindings: SelectionCompiler<'point'> = { defined: selCmpt => { @@ -54,7 +55,7 @@ const inputBindings: SelectionCompiler<'point'> = { signals: (model, selCmpt, signals) => { const name = selCmpt.name; const proj = selCmpt.project; - const signal = signals.filter(s => s.name === name + TUPLE)[0]; + const signal: NewSignal = signals.filter(s => s.name === name + TUPLE)[0]; const fields = name + TUPLE_FIELDS; const values = proj.items.map(p => varName(`${name}_${p.field}`)); const valid = values.map(v => `${v} !== null`).join(' && '); diff --git a/src/compile/selection/interval.ts b/src/compile/selection/interval.ts index a06b9c0ce2c..cda65f2b39e 100644 --- a/src/compile/selection/interval.ts +++ b/src/compile/selection/interval.ts @@ -1,11 +1,14 @@ -import {NewSignal, OnEvent, Stream} from 'vega'; +import {isObject, NewSignal, OnEvent, SignalValue, Stream} from 'vega'; import {array, stringValue} from 'vega-util'; import {SelectionCompiler, SelectionComponent, STORE, TUPLE, unitName} from '.'; -import {ScaleChannel, X, Y} from '../../channel'; +import {GeoPositionChannel, LATITUDE, LONGITUDE, ScaleChannel, X, Y} from '../../channel'; +import {FieldName} from '../../channeldef'; import {warn} from '../../log'; import {hasContinuousDomain} from '../../scale'; -import {SelectionInitInterval} from '../../selection'; -import {keys} from '../../util'; +import {IntervalSelectionConfigWithoutType, SelectionInitInterval, SELECTION_ID} from '../../selection'; +import {keys, vals} from '../../util'; +import {LayoutSizeIndex} from '../layoutsize/component'; +import {isUnitModel} from '../model'; import {UnitModel} from '../unit'; import {assembleInit} from './assemble'; import {SelectionProjection, TUPLE_FIELDS} from './project'; @@ -13,92 +16,183 @@ import scales from './scales'; export const BRUSH = '_brush'; export const SCALE_TRIGGER = '_scale_trigger'; +export const GEO_INIT_TICK = 'geo_interval_init_tick'; // Workaround for https://github.com/vega/vega/issues/3481 +const INIT = '_init'; +const CENTER = '_center'; + +// Separate type because the "fields" property is only used internally and we don't want to leak it to the schema. +export type IntervalSelectionConfigWithField = IntervalSelectionConfigWithoutType & {fields?: FieldName[]}; const interval: SelectionCompiler<'interval'> = { defined: selCmpt => selCmpt.type === 'interval', - signals: (model, selCmpt, signals) => { - const name = selCmpt.name; - const fieldsSg = name + TUPLE_FIELDS; - const hasScales = scales.defined(selCmpt); - const init = selCmpt.init ? selCmpt.init[0] : null; - const dataSignals: string[] = []; - const scaleTriggers: { - scaleName: string; - expr: string; - }[] = []; - - if (selCmpt.translate && !hasScales) { - const filterExpr = `!event.item || event.item.mark.name !== ${stringValue(name + BRUSH)}`; - events(selCmpt, (on: OnEvent[], evt: Stream) => { + parse: (model, selCmpt, selDef) => { + if (model.hasProjection) { + const def: IntervalSelectionConfigWithField = {...(isObject(selDef.select) ? selDef.select : {})}; + def.fields = [SELECTION_ID]; + if (!def.encodings) { + // Remap default x/y projection + def.encodings = selDef.value ? (keys(selDef.value) as GeoPositionChannel[]) : [LONGITUDE, LATITUDE]; + } + + selDef.select = {type: 'interval', ...def}; + } + + if (selCmpt.translate && !scales.defined(selCmpt)) { + const filterExpr = `!event.item || event.item.mark.name !== ${stringValue(selCmpt.name + BRUSH)}`; + for (const evt of selCmpt.events) { + if (!evt.between) { + warn(`${evt} is not an ordered event stream for interval selections.`); + continue; + } + const filters = array((evt.between[0].filter ??= [])); - if (!filters.includes(filterExpr)) { + if (filters.indexOf(filterExpr) < 0) { filters.push(filterExpr); } - return on; - }); + } } + }, + + signals: (model, selCmpt, signals) => { + const name = selCmpt.name; + const tupleSg = name + TUPLE; + const channels = vals(selCmpt.project.hasChannel).filter(p => p.channel === X || p.channel === Y); + const init = selCmpt.init ? selCmpt.init[0] : null; + + signals.push( + ...channels.reduce((arr, proj) => arr.concat(channelSignals(model, selCmpt, proj, init && init[proj.index])), []) + ); - selCmpt.project.items.forEach((proj, i) => { - const channel = proj.channel; - if (channel !== X && channel !== Y) { - warn('Interval selections only support x and y encoding channels.'); - return; + if (!model.hasProjection) { + // Proxy scale reactions to ensure that an infinite loop doesn't occur + // when an interval selection filter touches the scale. + if (!scales.defined(selCmpt)) { + const triggerSg = name + SCALE_TRIGGER; + const scaleTriggers = channels.map(proj => { + const channel = proj.channel as 'x' | 'y'; + const {data: dname, visual: vname} = proj.signals; + const scaleName = stringValue(model.scaleName(channel)); + const scaleType = model.getScaleComponent(channel).get('type'); + const toNum = hasContinuousDomain(scaleType) ? '+' : ''; + return ( + `(!isArray(${dname}) || ` + + `(${toNum}invert(${scaleName}, ${vname})[0] === ${toNum}${dname}[0] && ` + + `${toNum}invert(${scaleName}, ${vname})[1] === ${toNum}${dname}[1]))` + ); + }); + + if (scaleTriggers.length) { + signals.push({ + name: triggerSg, + value: {}, + on: [ + { + events: channels.map(proj => ({scale: model.scaleName(proj.channel)})), + update: scaleTriggers.join(' && ') + ` ? ${triggerSg} : {}` + } + ] + }); + } } - const val = init ? init[i] : null; - const cs = channelSignals(model, selCmpt, proj, val); - const dname = proj.signals.data; - const vname = proj.signals.visual; - const scaleName = stringValue(model.scaleName(channel)); - const scaleType = model.getScaleComponent(channel).get('type'); - const toNum = hasContinuousDomain(scaleType) ? '+' : ''; - - signals.push(...cs); - dataSignals.push(dname); - - scaleTriggers.push({ - scaleName: model.scaleName(channel), - expr: - `(!isArray(${dname}) || ` + - `(${toNum}invert(${scaleName}, ${vname})[0] === ${toNum}${dname}[0] && ` + - `${toNum}invert(${scaleName}, ${vname})[1] === ${toNum}${dname}[1]))` + // Only add an interval to the store if it has valid data extents. Data extents + // are set to null if pixel extents are equal to account for intervals over + // ordinal/nominal domains which, when inverted, will still produce a valid datum. + const dataSignals = channels.map(proj => proj.signals.data); + const update = `unit: ${unitName(model)}, fields: ${name + TUPLE_FIELDS}, values`; + return signals.concat({ + name: tupleSg, + ...(init ? {init: `{${update}: ${assembleInit(init)}}`} : {}), + ...(dataSignals.length + ? { + on: [ + { + events: [{signal: dataSignals.join(' || ')}], // Prevents double invocation, see https://github.com/vega/vega/issues/1672. + update: `${dataSignals.join(' && ')} ? {${update}: [${dataSignals}]} : null` + } + ] + } + : {}) }); - }); + } else { + const projection = stringValue(model.projectionName()); + const centerSg = model.projectionName() + CENTER; + const {x, y} = selCmpt.project.hasChannel; + const xvname = x && x.signals.visual; + const yvname = y && y.signals.visual; + const xinit = x ? init && init[x.index] : `${centerSg}[0]`; + const yinit = y ? init && init[y.index] : `${centerSg}[1]`; + const sizeSg = (layout: keyof LayoutSizeIndex) => model.getSizeSignalRef(layout).signal; + const bbox = + `[` + + `[${xvname ? xvname + '[0]' : '0'}, ${yvname ? yvname + '[0]' : '0'}],` + + `[${xvname ? xvname + '[1]' : sizeSg('width')}, ` + + `${yvname ? yvname + '[1]' : sizeSg('height')}]` + + `]`; + + if (init) { + signals.unshift({ + name: name + INIT, + init: + `[scale(${projection}, [${x ? xinit[0] : xinit}, ${y ? yinit[0] : yinit}]), ` + + `scale(${projection}, [${x ? xinit[1] : xinit}, ${y ? yinit[1] : yinit}])]` + }); - // Proxy scale reactions to ensure that an infinite loop doesn't occur - // when an interval selection filter touches the scale. - if (!hasScales && scaleTriggers.length) { - signals.push({ - name: name + SCALE_TRIGGER, - value: {}, + if (!x || !y) { + // If initializing a uni-dimensional brush, use the center of the view to determine the other coord + const hasCenterSg = signals.find(s => s.name === centerSg); + if (!hasCenterSg) { + signals.unshift({ + name: centerSg, + update: `invert(${projection}, [${sizeSg('width')}/2, ${sizeSg('height')}/2])` + }); + } + } + } + + const intersect = `intersect(${bbox}, {markname: ${stringValue(model.getName('marks'))}}, unit.mark)`; + const base = `{unit: ${unitName(model)}}`; + const update = `vlSelectionTuples(${intersect}, ${base})`; + const visualSignals = channels.map(proj => proj.signals.visual); + + return signals.concat({ + name: tupleSg, on: [ { - events: scaleTriggers.map(t => ({scale: t.scaleName})), - update: `${scaleTriggers.map(t => t.expr).join(' && ')} ? ${name + SCALE_TRIGGER} : {}` + events: [ + ...(visualSignals.length ? [{signal: visualSignals.join(' || ')}] : []), + ...(init ? [{signal: GEO_INIT_TICK}] : []) + ], + update } ] }); } + }, - // Only add an interval to the store if it has valid data extents. Data extents - // are set to null if pixel extents are equal to account for intervals over - // ordinal/nominal domains which, when inverted, will still produce a valid datum. - const update = `unit: ${unitName(model)}, fields: ${fieldsSg}, values`; - return signals.concat({ - name: name + TUPLE, - ...(init ? {init: `{${update}: ${assembleInit(init)}}`} : {}), - ...(dataSignals.length - ? { - on: [ - { - events: [{signal: dataSignals.join(' || ')}], // Prevents double invocation, see https://github.com/vega/vega#1672. - update: `${dataSignals.join(' && ')} ? {${update}: [${dataSignals}]} : null` - } - ] - } - : {}) - }); + topLevelSignals: (model, selCmpt, signals) => { + if (isUnitModel(model) && model.hasProjection && selCmpt.init) { + // Workaround for https://github.com/vega/vega/issues/3481 + // The scenegraph isn't populated on the first pulse. So we use a timer signal + // to re-pulse the dataflow as soon as possible. We return an object to ensure + // this only occurs once. + const hasTick = signals.filter(s => s.name === GEO_INIT_TICK); + if (!hasTick.length) { + signals.unshift({ + name: GEO_INIT_TICK, + value: null, + on: [ + { + events: 'timer{1}', + update: `${GEO_INIT_TICK} === null ? {} : ${GEO_INIT_TICK}` + } + ] + }); + } + } + + return signals; }, marks: (model, selCmpt, marks) => { @@ -192,62 +286,59 @@ function channelSignals( model: UnitModel, selCmpt: SelectionComponent<'interval'>, proj: SelectionProjection, - init?: SelectionInitInterval + init: SelectionInitInterval ): NewSignal[] { + const scaledInterval = !model.hasProjection; const channel = proj.channel; const vname = proj.signals.visual; - const dname = proj.signals.data; - const hasScales = scales.defined(selCmpt); - const scaleName = stringValue(model.scaleName(channel)); - const scale = model.getScaleComponent(channel as ScaleChannel); - const scaleType = scale ? scale.get('type') : undefined; + + const scaleName = stringValue(scaledInterval ? model.scaleName(channel) : model.projectionName()); const scaled = (str: string) => `scale(${scaleName}, ${str})`; + const size = model.getSizeSignalRef(channel === X ? 'width' : 'height').signal; const coord = `${channel}(unit)`; - - const on = events(selCmpt, (def: OnEvent[], evt: Stream) => { + const von = selCmpt.events.reduce((def: OnEvent[], evt: Stream) => { return [ ...def, {events: evt.between[0], update: `[${coord}, ${coord}]`}, // Brush Start {events: evt, update: `[${vname}[0], clamp(${coord}, 0, ${size})]`} // Brush End ]; - }); - - // React to pan/zooms of continuous scales. Non-continuous scales - // (band, point) cannot be pan/zoomed and any other changes - // to their domains (e.g., filtering) should clear the brushes. - on.push({ - events: {signal: selCmpt.name + SCALE_TRIGGER}, - update: hasContinuousDomain(scaleType) ? `[${scaled(`${dname}[0]`)}, ${scaled(`${dname}[1]`)}]` : `[0, 0]` - }); - - return hasScales - ? [{name: dname, on: []}] - : [ - { - name: vname, - ...(init ? {init: assembleInit(init, true, scaled)} : {value: []}), - on - }, - { - name: dname, - ...(init ? {init: assembleInit(init)} : {}), // Cannot be `value` as `init` may require datetime exprs. - on: [ - { - events: {signal: vname}, - update: `${vname}[0] === ${vname}[1] ? null : invert(${scaleName}, ${vname})` - } - ] - } - ]; -} + }, []); -function events(selCmpt: SelectionComponent<'interval'>, cb: (def: OnEvent[], evt: Stream) => OnEvent[]): OnEvent[] { - return selCmpt.events.reduce((on, evt) => { - if (!evt.between) { - warn(`${evt} is not an ordered event stream for interval selections.`); - return on; - } - return cb(on, evt); - }, [] as OnEvent[]); + if (scaledInterval) { + const dname = proj.signals.data; + const hasScales = scales.defined(selCmpt); + const scale = model.getScaleComponent(channel as ScaleChannel); + const scaleType = scale ? scale.get('type') : undefined; + const vinit: SignalValue = init ? {init: assembleInit(init, true, scaled)} : {value: []}; + + // React to pan/zooms of continuous scales. Non-continuous scales + // (band, point) cannot be pan/zoomed and any other changes + // to their domains (e.g., filtering) should clear the brushes. + von.push({ + events: {signal: selCmpt.name + SCALE_TRIGGER}, + update: hasContinuousDomain(scaleType) ? `[${scaled(`${dname}[0]`)}, ${scaled(`${dname}[1]`)}]` : `[0, 0]` + }); + + return hasScales + ? [{name: dname, on: []}] + : [ + {name: vname, ...vinit, on: von}, + { + name: dname, + ...(init ? {init: assembleInit(init)} : {}), // Cannot be `value` as `init` may require datetime exprs. + on: [ + { + events: {signal: vname}, + update: `${vname}[0] === ${vname}[1] ? null : invert(${scaleName}, ${vname})` + } + ] + } + ]; + } else { + const initIdx = channel === X ? 0 : 1; + const initSg = selCmpt.name + INIT; + const vinit: SignalValue = init ? {init: `[${initSg}[0][${initIdx}], ${initSg}[1][${initIdx}]]`} : {value: []}; + return [{name: vname, ...vinit, on: von}]; + } } diff --git a/src/compile/selection/legends.ts b/src/compile/selection/legends.ts index a649383b1cf..ad9a51876ea 100644 --- a/src/compile/selection/legends.ts +++ b/src/compile/selection/legends.ts @@ -1,4 +1,4 @@ -import {isObject, MergedStream, Stream} from 'vega'; +import {isObject, MergedStream, NewSignal, Stream} from 'vega'; import {parseSelector} from 'vega-event-selector'; import {array, isString} from 'vega-util'; import {disableDirectManipulation, TUPLE} from '.'; @@ -85,7 +85,7 @@ const legendBindings: SelectionCompiler<'point'> = { signals: (model, selCmpt, signals) => { const name = selCmpt.name; const proj = selCmpt.project; - const tuple = signals.find(s => s.name === name + TUPLE); + const tuple: NewSignal = signals.find(s => s.name === name + TUPLE); const fields = name + TUPLE_FIELDS; const values = proj.items.filter(p => p.hasLegend).map(p => varName(`${name}_${varName(p.field)}_legend`)); const valid = values.map(v => `${v} !== null`).join(' && '); diff --git a/src/compile/selection/parse.ts b/src/compile/selection/parse.ts index 554ef8fa365..d816af15057 100644 --- a/src/compile/selection/parse.ts +++ b/src/compile/selection/parse.ts @@ -39,7 +39,7 @@ export function parseUnitSelection(model: UnitModel, selDefs: SelectionParameter } if (defaults[key] === undefined || defaults[key] === true) { - defaults[key] = cfg[key] ?? defaults[key]; + defaults[key] = duplicate(cfg[key] ?? defaults[key]); } } @@ -52,9 +52,10 @@ export function parseUnitSelection(model: UnitModel, selDefs: SelectionParameter events: isString(defaults.on) ? parseSelector(defaults.on, 'scope') : array(duplicate(defaults.on)) } as any); + const def_ = duplicate(def); // defensive copy to prevent compilers from causing side effects for (const c of selectionCompilers) { if (c.defined(selCmpt) && c.parse) { - c.parse(model, selCmpt, def); + c.parse(model, selCmpt, def_); } } } diff --git a/src/compile/selection/project.ts b/src/compile/selection/project.ts index 706e75ea168..9cfd1ece1cf 100644 --- a/src/compile/selection/project.ts +++ b/src/compile/selection/project.ts @@ -1,11 +1,19 @@ import {array, isObject} from 'vega-util'; -import {isSingleDefUnitChannel, ScaleChannel, SingleDefUnitChannel} from '../../channel'; +import { + GeoPositionChannel, + getPositionChannelFromLatLong, + isGeoPositionChannel, + isScaleChannel, + isSingleDefUnitChannel, + SingleDefUnitChannel +} from '../../channel'; import * as log from '../../log'; import {hasContinuousDomain} from '../../scale'; import {PointSelectionConfig, SelectionInitIntervalMapping, SelectionInitMapping, SELECTION_ID} from '../../selection'; -import {Dict, hash, keys, replacePathInField, varName, isEmpty} from '../../util'; +import {Dict, hash, keys, varName, isEmpty} from '../../util'; import {TimeUnitComponent, TimeUnitNode} from '../data/timeunit'; import {SelectionCompiler} from '.'; +import {assembleProjection} from './assemble'; export const TUPLE_FIELDS = '_tuple_fields'; /** @@ -22,7 +30,9 @@ export type TupleStoreType = export interface SelectionProjection { type: TupleStoreType; field: string; + index: number; channel?: SingleDefUnitChannel; + geoChannel?: GeoPositionChannel; signals?: {data?: string; visual?: string}; hasLegend?: boolean; } @@ -86,10 +96,10 @@ const project: SelectionCompiler = { (encodings || (encodings = [])).push(key as SingleDefUnitChannel); } else { if (type === 'interval') { - log.warn(log.message.INTERVAL_INITIALIZED_WITH_X_Y); + log.warn(log.message.INTERVAL_INITIALIZED_WITH_POS); encodings = cfg.encodings; } else { - (fields || (fields = [])).push(key); + (fields ??= []).push(key); } } } @@ -140,21 +150,28 @@ const project: SelectionCompiler = { // Determine whether the tuple will store enumerated or ranged values. // Interval selections store ranges for continuous scales, and enumerations otherwise. // Single/multi selections store ranges for binned fields, and enumerations otherwise. - let tplType: TupleStoreType = 'E'; - if (type === 'interval') { - const scaleType = model.getScaleComponent(channel as ScaleChannel).get('type'); - if (hasContinuousDomain(scaleType)) { - tplType = 'R'; - } - } else if (fieldDef.bin) { - tplType = 'R-RE'; - } - - const p: SelectionProjection = {field, channel, type: tplType}; + const tplType: TupleStoreType = + type === 'interval' && + isScaleChannel(channel) && + hasContinuousDomain(model.getScaleComponent(channel).get('type')) + ? 'R' + : fieldDef.bin + ? 'R-RE' + : 'E'; + + const p: SelectionProjection = {field, channel, type: tplType, index: proj.items.length}; p.signals = {...signalName(p, 'data'), ...signalName(p, 'visual')}; proj.items.push((parsed[field] = p)); - proj.hasField[field] = proj.hasChannel[channel] = parsed[field]; + proj.hasField[field] = parsed[field]; proj.hasSelectionId = proj.hasSelectionId || field === SELECTION_ID; + + if (isGeoPositionChannel(channel)) { + p.geoChannel = channel; + p.channel = getPositionChannelFromLatLong(channel); + proj.hasChannel[p.channel] = parsed[field]; + } else { + proj.hasChannel[channel] = parsed[field]; + } } } else { log.warn(log.message.cannotProjectOnChannelWithoutField(channel)); @@ -163,7 +180,7 @@ const project: SelectionCompiler = { for (const field of fields ?? []) { if (proj.hasField[field]) continue; - const p: SelectionProjection = {type: 'E', field}; + const p: SelectionProjection = {type: 'E', field, index: proj.items.length}; p.signals = {...signalName(p, 'data')}; proj.items.push(p); proj.hasField[field] = p; @@ -174,7 +191,9 @@ const project: SelectionCompiler = { selCmpt.init = (init as any).map((v: SelectionInitMapping | SelectionInitIntervalMapping) => { // Selections can be initialized either with a full object that maps projections to values // or scalar values to smoothen the abstraction gradient from variable params to point selections. - return proj.items.map(p => (isObject(v) ? (v[p.channel] !== undefined ? v[p.channel] : v[p.field]) : v)); + return proj.items.map(p => + isObject(v) ? (v[p.geoChannel || p.channel] !== undefined ? v[p.geoChannel || p.channel] : v[p.field]) : v + ); }); } @@ -190,11 +209,7 @@ const project: SelectionCompiler = { ? allSignals : allSignals.concat({ name, - value: selCmpt.project.items.map(proj => { - const {signals, hasLegend, ...rest} = proj; - rest.field = replacePathInField(rest.field); - return rest; - }) + value: selCmpt.project.items.map(assembleProjection) }); } }; diff --git a/src/compile/selection/scales.ts b/src/compile/selection/scales.ts index d05ebccda69..d716bfa20e0 100644 --- a/src/compile/selection/scales.ts +++ b/src/compile/selection/scales.ts @@ -8,6 +8,7 @@ import {UnitModel} from '../unit'; import {SelectionProjection} from './project'; import {SelectionCompiler} from '.'; import {replacePathInField} from '../../util'; +import {NewSignal} from 'vega'; const scaleBindings: SelectionCompiler<'interval'> = { defined: selCmpt => { @@ -52,7 +53,7 @@ const scaleBindings: SelectionCompiler<'interval'> = { // state is captured by the top-level signals that we insert and "push // outer" to from within the units. We need to reassemble this state into // the top-level named signal, except no single selCmpt has a global view. - const namedSg = signals.filter(s => s.name === selCmpt.name)[0]; + const namedSg: NewSignal = signals.filter(s => s.name === selCmpt.name)[0]; let update = namedSg.update; if (update.indexOf(VL_SELECTION_RESOLVE) >= 0) { namedSg.update = `{${bound diff --git a/src/compile/selection/translate.ts b/src/compile/selection/translate.ts index f412e5fab50..0c2602c6e64 100644 --- a/src/compile/selection/translate.ts +++ b/src/compile/selection/translate.ts @@ -18,12 +18,12 @@ const translate: SelectionCompiler<'interval'> = { signals: (model, selCmpt, signals) => { const name = selCmpt.name; - const hasScales = scalesCompiler.defined(selCmpt); + const boundScales = scalesCompiler.defined(selCmpt); const anchor = name + ANCHOR; const {x, y} = selCmpt.project.hasChannel; let events = parseSelector(selCmpt.translate, 'scope'); - if (!hasScales) { + if (!boundScales) { events = events.map(e => ((e.between[0].markname = name + INTERVAL_BRUSH), e)); } @@ -36,8 +36,8 @@ const translate: SelectionCompiler<'interval'> = { events: events.map(e => e.between[0]), update: '{x: x(unit), y: y(unit)' + - (x !== undefined ? `, extent_x: ${hasScales ? domain(model, X) : `slice(${x.signals.visual})`}` : '') + - (y !== undefined ? `, extent_y: ${hasScales ? domain(model, Y) : `slice(${y.signals.visual})`}` : '') + + (x !== undefined ? `, extent_x: ${boundScales ? domain(model, X) : `slice(${x.signals.visual})`}` : '') + + (y !== undefined ? `, extent_y: ${boundScales ? domain(model, Y) : `slice(${y.signals.visual})`}` : '') + '}' } ] @@ -79,25 +79,26 @@ function onDelta( const anchor = name + ANCHOR; const delta = name + DELTA; const channel = proj.channel as ScaleChannel; - const hasScales = scalesCompiler.defined(selCmpt); - const signal = signals.filter(s => s.name === proj.signals[hasScales ? 'data' : 'visual'])[0]; + const boundScales = scalesCompiler.defined(selCmpt); + const signal = signals.filter(s => s.name === proj.signals[boundScales ? 'data' : 'visual'])[0]; const sizeSg = model.getSizeSignalRef(size).signal; const scaleCmpt = model.getScaleComponent(channel); - const scaleType = scaleCmpt.get('type'); - const reversed = scaleCmpt.get('reverse'); // scale parsing sets this flag for fieldDef.sort - const sign = !hasScales ? '' : channel === X ? (reversed ? '' : '-') : reversed ? '-' : ''; + const scaleType = scaleCmpt && scaleCmpt.get('type'); + const reversed = scaleCmpt && scaleCmpt.get('reverse'); // scale parsing sets this flag for fieldDef.sort + const sign = !boundScales ? '' : channel === X ? (reversed ? '' : '-') : reversed ? '-' : ''; const extent = `${anchor}.extent_${channel}`; - const offset = `${sign}${delta}.${channel} / ${hasScales ? `${sizeSg}` : `span(${extent})`}`; - const panFn = !hasScales - ? 'panLinear' - : scaleType === 'log' - ? 'panLog' - : scaleType === 'symlog' - ? 'panSymlog' - : scaleType === 'pow' - ? 'panPow' - : 'panLinear'; - const arg = !hasScales + const offset = `${sign}${delta}.${channel} / ${boundScales ? `${sizeSg}` : `span(${extent})`}`; + const panFn = + !boundScales || !scaleCmpt + ? 'panLinear' + : scaleType === 'log' + ? 'panLog' + : scaleType === 'symlog' + ? 'panSymlog' + : scaleType === 'pow' + ? 'panPow' + : 'panLinear'; + const arg = !boundScales ? '' : scaleType === 'pow' ? `, ${scaleCmpt.get('exponent') ?? 1}` @@ -108,6 +109,6 @@ function onDelta( signal.on.push({ events: {signal: delta}, - update: hasScales ? update : `clampRange(${update}, 0, ${sizeSg})` + update: boundScales ? update : `clampRange(${update}, 0, ${sizeSg})` }); } diff --git a/src/compile/selection/zoom.ts b/src/compile/selection/zoom.ts index accdfc30773..3b3e6ce2ec5 100644 --- a/src/compile/selection/zoom.ts +++ b/src/compile/selection/zoom.ts @@ -19,14 +19,14 @@ const zoom: SelectionCompiler<'interval'> = { signals: (model, selCmpt, signals) => { const name = selCmpt.name; - const hasScales = scalesCompiler.defined(selCmpt); + const boundScales = scalesCompiler.defined(selCmpt); const delta = name + DELTA; const {x, y} = selCmpt.project.hasChannel; const sx = stringValue(model.scaleName(X)); const sy = stringValue(model.scaleName(Y)); let events = parseSelector(selCmpt.zoom, 'scope'); - if (!hasScales) { + if (!boundScales) { events = events.map(e => ((e.markname = name + INTERVAL_BRUSH), e)); } @@ -36,7 +36,7 @@ const zoom: SelectionCompiler<'interval'> = { on: [ { events, - update: !hasScales + update: !boundScales ? `{x: x(unit), y: y(unit)}` : '{' + [sx ? `x: invert(${sx}, x(unit))` : '', sy ? `y: invert(${sy}, y(unit))` : ''] @@ -81,24 +81,25 @@ function onDelta( ) { const name = selCmpt.name; const channel = proj.channel as ScaleChannel; - const hasScales = scalesCompiler.defined(selCmpt); - const signal = signals.filter(s => s.name === proj.signals[hasScales ? 'data' : 'visual'])[0]; + const boundScales = scalesCompiler.defined(selCmpt); + const signal = signals.filter(s => s.name === proj.signals[boundScales ? 'data' : 'visual'])[0]; const sizeSg = model.getSizeSignalRef(size).signal; const scaleCmpt = model.getScaleComponent(channel); - const scaleType = scaleCmpt.get('type'); - const base = hasScales ? domain(model, channel) : signal.name; + const scaleType = scaleCmpt && scaleCmpt.get('type'); + const base = boundScales ? domain(model, channel) : signal.name; const delta = name + DELTA; const anchor = `${name}${ANCHOR}.${channel}`; - const zoomFn = !hasScales - ? 'zoomLinear' - : scaleType === 'log' - ? 'zoomLog' - : scaleType === 'symlog' - ? 'zoomSymlog' - : scaleType === 'pow' - ? 'zoomPow' - : 'zoomLinear'; - const arg = !hasScales + const zoomFn = + !boundScales || !scaleCmpt + ? 'zoomLinear' + : scaleType === 'log' + ? 'zoomLog' + : scaleType === 'symlog' + ? 'zoomSymlog' + : scaleType === 'pow' + ? 'zoomPow' + : 'zoomLinear'; + const arg = !boundScales ? '' : scaleType === 'pow' ? `, ${scaleCmpt.get('exponent') ?? 1}` @@ -109,6 +110,6 @@ function onDelta( signal.on.push({ events: {signal: delta}, - update: hasScales ? update : `clampRange(${update}, 0, ${sizeSg})` + update: boundScales ? update : `clampRange(${update}, 0, ${sizeSg})` }); } diff --git a/src/compile/unit.ts b/src/compile/unit.ts index 6ccf1384fc7..c13ebde5b33 100644 --- a/src/compile/unit.ts +++ b/src/compile/unit.ts @@ -281,7 +281,7 @@ export class UnitModel extends ModelWithField { if (this.encoding.x || this.encoding.y) { return 'cell'; } else { - return undefined; + return 'view'; } } diff --git a/src/log/message.ts b/src/log/message.ts index c64a20c44df..adb059e2fe9 100644 --- a/src/log/message.ts +++ b/src/log/message.ts @@ -97,7 +97,8 @@ export function noSameUnitLookup(name: string) { export const NEEDS_SAME_SELECTION = 'The same selection must be used to override scale domains in a layered view.'; -export const INTERVAL_INITIALIZED_WITH_X_Y = 'Interval selections should be initialized using "x" and/or "y" keys.'; +export const INTERVAL_INITIALIZED_WITH_POS = + 'Interval selections should be initialized using "x", "y", "longitude", or "latitude" keys.'; // REPEAT export function noSuchRepeatedValue(field: string) { diff --git a/test-runtime/interval.test.ts b/test-runtime/interval.test.ts index f16ff1a48c4..1ece7a2dd2a 100644 --- a/test-runtime/interval.test.ts +++ b/test-runtime/interval.test.ts @@ -1,6 +1,6 @@ import {TopLevelSpec} from '../src'; import {SelectionType} from '../src/selection'; -import {brush, embedFn, hits as hitsMaster, spec, testRenderFn, tuples} from './util'; +import {brush, embedFn, geoSpec, hits as hitsMaster, spec, testRenderFn, tuples} from './util'; import {Page} from 'puppeteer/lib/cjs/puppeteer/common/Page'; describe('interval selections at runtime in unit views', () => { @@ -197,4 +197,26 @@ describe('interval selections at runtime in unit views', () => { await testRender(`logpow_${i}`); } }); + + describe('geo-intervals', () => { + it('should add IDs to the store', async () => { + await embed(geoSpec()); + const store = await page.evaluate(brush('drag', 1)); + expect(store).toHaveLength(13); + for (const t of store) { + expect(t).toHaveProperty('_vgsid_'); + } + await testRender(`geo_1`); + }); + + it('should respect projections', async () => { + await embed(geoSpec({encodings: ['longitude']})); + const store = await page.evaluate(brush('drag', 0)); + expect(store).toHaveLength(20); + for (const t of store) { + expect(t).toHaveProperty('_vgsid_'); + } + await testRender(`geo_0`); + }); + }); }); diff --git a/test-runtime/resources/interval/translate/geo-0.svg b/test-runtime/resources/interval/translate/geo-0.svg new file mode 100644 index 00000000000..520738812d6 --- /dev/null +++ b/test-runtime/resources/interval/translate/geo-0.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test-runtime/resources/interval/translate/geo-1.svg b/test-runtime/resources/interval/translate/geo-1.svg new file mode 100644 index 00000000000..3d5cea9393d --- /dev/null +++ b/test-runtime/resources/interval/translate/geo-1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test-runtime/resources/interval/translate/geo-2.svg b/test-runtime/resources/interval/translate/geo-2.svg new file mode 100644 index 00000000000..ec05c730b5c --- /dev/null +++ b/test-runtime/resources/interval/translate/geo-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test-runtime/resources/interval/unit/geo_0.svg b/test-runtime/resources/interval/unit/geo_0.svg new file mode 100644 index 00000000000..c135608c7bd --- /dev/null +++ b/test-runtime/resources/interval/unit/geo_0.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test-runtime/resources/interval/unit/geo_1.svg b/test-runtime/resources/interval/unit/geo_1.svg new file mode 100644 index 00000000000..520738812d6 --- /dev/null +++ b/test-runtime/resources/interval/unit/geo_1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test-runtime/resources/interval/zoom/geo-0.svg b/test-runtime/resources/interval/zoom/geo-0.svg new file mode 100644 index 00000000000..520738812d6 --- /dev/null +++ b/test-runtime/resources/interval/zoom/geo-0.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test-runtime/resources/interval/zoom/geo-1.svg b/test-runtime/resources/interval/zoom/geo-1.svg new file mode 100644 index 00000000000..2a8697a2171 --- /dev/null +++ b/test-runtime/resources/interval/zoom/geo-1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test-runtime/resources/interval/zoom/geo-2.svg b/test-runtime/resources/interval/zoom/geo-2.svg new file mode 100644 index 00000000000..bba75f43570 --- /dev/null +++ b/test-runtime/resources/interval/zoom/geo-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test-runtime/translate.test.ts b/test-runtime/translate.test.ts index 2f944c8fd31..ba0c7f3cd9b 100644 --- a/test-runtime/translate.test.ts +++ b/test-runtime/translate.test.ts @@ -6,6 +6,7 @@ import { brush, compositeTypes, embedFn, + geoSpec, hits as hitsMaster, parentSelector, spec, @@ -16,117 +17,97 @@ import { import {Page} from 'puppeteer/lib/cjs/puppeteer/common/Page'; import {TopLevelSpec} from '../src'; -for (const bind of [bound, unbound]) { - describe(`Translate ${bind} interval selections at runtime`, () => { - let page: Page; - let embed: (specification: TopLevelSpec) => Promise; - let testRender: (filename: string) => Promise; - - beforeAll(async () => { - page = await (global as any).__BROWSER__.newPage(); - embed = embedFn(page); - testRender = testRenderFn(page, `interval/translate/${bind}`); - await page.goto('http://0.0.0.0:8000/test-runtime/'); - }); +describe('Translate interval selections at runtime', () => { + let page: Page; + let embed: (specification: TopLevelSpec) => Promise; + let testRender: (filename: string) => Promise; - afterAll(async () => { - await page.close(); - }); + beforeAll(async () => { + page = await (global as any).__BROWSER__.newPage(); + embed = embedFn(page); + await page.goto('http://0.0.0.0:8000/test-runtime/'); + }); - const type = 'interval'; - const hits = hitsMaster.interval; - const binding = bind === bound ? {bind: 'scales'} : {}; - - const assertExtent = { - [unbound]: { - x: ['isAbove', 'isBelow'], - y: ['isBelow', 'isAbove'] - }, - [bound]: { - x: ['isBelow', 'isAbove'], - y: ['isAbove', 'isBelow'] - } - }; - - it('should move back-and-forth', async () => { - for (let i = 0; i < hits.translate.length; i++) { - await embed(spec('unit', i, {type, ...binding})); - const drag = (await page.evaluate(brush('drag', i)))[0]; - await testRender(`${i}-0`); - const translate = (await page.evaluate(brush('translate', i, null, bind === unbound)))[0]; - assert[assertExtent[bind].x[i]](translate.values[0][0], drag.values[0][0]); - assert[assertExtent[bind].x[i]](translate.values[0][1], drag.values[0][1]); - assert[assertExtent[bind].y[i]](translate.values[1][0], drag.values[1][0]); - assert[assertExtent[bind].y[i]](translate.values[1][1], drag.values[1][1]); - await testRender(`${i}-1`); - } - }); + afterAll(async () => { + await page.close(); + }); - it('should work with binned domains', async () => { - for (let i = 0; i < hits.bins.length; i++) { - await embed( - spec( - 'unit', - 1, - {type, ...binding, encodings: ['y']}, - { - x: {aggregate: 'count', type: 'quantitative'}, - y: {bin: true}, - color: {value: 'steelblue', field: null, type: null} - } - ) - ); - const drag = (await page.evaluate(brush('bins', i)))[0]; - await testRender(`bins_${i}-0`); - const translate = (await page.evaluate(brush('bins_translate', i, null, bind === unbound)))[0]; - assert[assertExtent[bind].y[i]](translate.values[0][0], drag.values[0][0]); - assert[assertExtent[bind].y[i]](translate.values[0][1], drag.values[0][1]); - await testRender(`bins_${i}-1`); - } - }); + const hits = hitsMaster.interval; - it('should work with temporal domains', async () => { - // await jestPuppeteer.debug(); - const values = tuples.map(d => ({...d, a: new Date(2017, d.a)})); - const toNumber = (a: any) => a[0].values[0].map((d: any) => +d); - - for (let i = 0; i < hits.translate.length; i++) { - await embed(spec('unit', i, {type, ...binding, encodings: ['x']}, {values, x: {type: 'temporal'}})); - const drag = toNumber(await page.evaluate(brush('drag', i))); - await testRender(`temporal_${i}-0`); - const translate = toNumber(await page.evaluate(brush('translate', i, null, bind === unbound))); - assert[assertExtent[bind].x[i]](translate[0], drag[0]); - assert[assertExtent[bind].x[i]](translate[1], drag[1]); - await testRender(`temporal_${i}-1`); - } - }); + for (const bind of [bound, unbound]) { + describe(`${bind} intervals`, () => { + beforeAll(() => { + testRender = testRenderFn(page, `interval/translate/${bind}`); + }); - it('should work with log/pow scales', async () => { - for (let i = 0; i < hits.translate.length; i++) { - await embed( - spec( - 'unit', - i, - {type, ...binding}, - { - x: {scale: {type: 'pow', exponent: 1.5}}, - y: {scale: {type: 'log'}} - } - ) - ); - const drag = (await page.evaluate(brush('drag', i)))[0]; - await testRender(`logpow_${i}-0`); - const translate = (await page.evaluate(brush('translate', i, null, bind === unbound)))[0]; - assert[assertExtent[bind].x[i]](translate.values[0][0], drag.values[0][0]); - assert[assertExtent[bind].x[i]](translate.values[0][1], drag.values[0][1]); - assert[assertExtent[bind].y[i]](translate.values[1][0], drag.values[1][0]); - assert[assertExtent[bind].y[i]](translate.values[1][1], drag.values[1][1]); - await testRender(`logpow_${i}-1`); - } - }); + const type = 'interval'; + const binding = bind === bound ? {bind: 'scales'} : {}; - if (bind === unbound) { - it('should work with ordinal/nominal domains', async () => { + const assertExtent = { + [unbound]: { + x: ['isAbove', 'isBelow'], + y: ['isBelow', 'isAbove'] + }, + [bound]: { + x: ['isBelow', 'isAbove'], + y: ['isAbove', 'isBelow'] + } + }; + + it('should move back-and-forth', async () => { + for (let i = 0; i < hits.translate.length; i++) { + await embed(spec('unit', i, {type, ...binding})); + const drag = (await page.evaluate(brush('drag', i)))[0]; + await testRender(`${i}-0`); + const translate = (await page.evaluate(brush('translate', i, null, bind === unbound)))[0]; + assert[assertExtent[bind].x[i]](translate.values[0][0], drag.values[0][0]); + assert[assertExtent[bind].x[i]](translate.values[0][1], drag.values[0][1]); + assert[assertExtent[bind].y[i]](translate.values[1][0], drag.values[1][0]); + assert[assertExtent[bind].y[i]](translate.values[1][1], drag.values[1][1]); + await testRender(`${i}-1`); + } + }); + + it('should work with binned domains', async () => { + for (let i = 0; i < hits.bins.length; i++) { + await embed( + spec( + 'unit', + 1, + {type, ...binding, encodings: ['y']}, + { + x: {aggregate: 'count', type: 'quantitative'}, + y: {bin: true}, + color: {value: 'steelblue', field: null, type: null} + } + ) + ); + const drag = (await page.evaluate(brush('bins', i)))[0]; + await testRender(`bins_${i}-0`); + const translate = (await page.evaluate(brush('bins_translate', i, null, bind === unbound)))[0]; + assert[assertExtent[bind].y[i]](translate.values[0][0], drag.values[0][0]); + assert[assertExtent[bind].y[i]](translate.values[0][1], drag.values[0][1]); + await testRender(`bins_${i}-1`); + } + }); + + it('should work with temporal domains', async () => { + // await jestPuppeteer.debug(); + const values = tuples.map(d => ({...d, a: new Date(2017, d.a)})); + const toNumber = (a: any) => a[0].values[0].map((d: any) => +d); + + for (let i = 0; i < hits.translate.length; i++) { + await embed(spec('unit', i, {type, ...binding, encodings: ['x']}, {values, x: {type: 'temporal'}})); + const drag = toNumber(await page.evaluate(brush('drag', i))); + await testRender(`temporal_${i}-0`); + const translate = toNumber(await page.evaluate(brush('translate', i, null, bind === unbound))); + assert[assertExtent[bind].x[i]](translate[0], drag[0]); + assert[assertExtent[bind].x[i]](translate[1], drag[1]); + await testRender(`temporal_${i}-1`); + } + }); + + it('should work with log/pow scales', async () => { for (let i = 0; i < hits.translate.length; i++) { await embed( spec( @@ -134,48 +115,89 @@ for (const bind of [bound, unbound]) { i, {type, ...binding}, { - x: {type: 'ordinal'}, - y: {type: 'nominal'} + x: {scale: {type: 'pow', exponent: 1.5}}, + y: {scale: {type: 'log'}} } ) ); const drag = (await page.evaluate(brush('drag', i)))[0]; - await testRender(`ord_${i}-0`); - const translate = (await page.evaluate(brush('translate', i, null, true)))[0]; + await testRender(`logpow_${i}-0`); + const translate = (await page.evaluate(brush('translate', i, null, bind === unbound)))[0]; assert[assertExtent[bind].x[i]](translate.values[0][0], drag.values[0][0]); assert[assertExtent[bind].x[i]](translate.values[0][1], drag.values[0][1]); assert[assertExtent[bind].y[i]](translate.values[1][0], drag.values[1][0]); assert[assertExtent[bind].y[i]](translate.values[1][1], drag.values[1][1]); - await testRender(`ord_${i}-1`); + await testRender(`logpow_${i}-1`); } }); - } else { - for (const specType of compositeTypes) { - const assertExtents = { - repeat: { - x: ['isBelow', 'isBelow', 'isBelow'], - y: ['isAbove', 'isAbove', 'isAbove'] - }, - facet: { - x: ['isBelow', 'isBelow', 'isBelow'], - y: ['isBelow', 'isAbove', 'isBelow'] - } - }; - it(`should work with shared scales in ${specType} views`, async () => { - for (let i = 0; i < hits[specType].length; i++) { - await embed(spec(specType, 0, {type, ...binding}, {resolve: {scale: {x: 'shared', y: 'shared'}}})); - const parent = parentSelector(specType, i); - const xscale = await page.evaluate('view._runtime.scales.x.value.domain()'); - const yscale = await page.evaluate('view._runtime.scales.y.value.domain()'); - const drag = (await page.evaluate(brush(specType, i, parent)))[0]; - assert[assertExtents[specType].x[i]](drag.values[0][0], xscale[0], `iter: ${i}`); - assert[assertExtents[specType].x[i]](drag.values[0][1], xscale[1], `iter: ${i}`); - assert[assertExtents[specType].y[i]](drag.values[1][0], yscale[0], `iter: ${i}`); - assert[assertExtents[specType].y[i]](drag.values[1][1], yscale[1], `iter: ${i}`); - await testRender(`${specType}_${i}`); + + if (bind === unbound) { + it('should work with ordinal/nominal domains', async () => { + for (let i = 0; i < hits.translate.length; i++) { + await embed( + spec( + 'unit', + i, + {type, ...binding}, + { + x: {type: 'ordinal'}, + y: {type: 'nominal'} + } + ) + ); + const drag = (await page.evaluate(brush('drag', i)))[0]; + await testRender(`ord_${i}-0`); + const translate = (await page.evaluate(brush('translate', i, null, true)))[0]; + assert[assertExtent[bind].x[i]](translate.values[0][0], drag.values[0][0]); + assert[assertExtent[bind].x[i]](translate.values[0][1], drag.values[0][1]); + assert[assertExtent[bind].y[i]](translate.values[1][0], drag.values[1][0]); + assert[assertExtent[bind].y[i]](translate.values[1][1], drag.values[1][1]); + await testRender(`ord_${i}-1`); } }); + } else { + for (const specType of compositeTypes) { + const assertExtents = { + repeat: { + x: ['isBelow', 'isBelow', 'isBelow'], + y: ['isAbove', 'isAbove', 'isAbove'] + }, + facet: { + x: ['isBelow', 'isBelow', 'isBelow'], + y: ['isBelow', 'isAbove', 'isBelow'] + } + }; + it(`should work with shared scales in ${specType} views`, async () => { + for (let i = 0; i < hits[specType].length; i++) { + await embed(spec(specType, 0, {type, ...binding}, {resolve: {scale: {x: 'shared', y: 'shared'}}})); + const parent = parentSelector(specType, i); + const xscale = await page.evaluate('view._runtime.scales.x.value.domain()'); + const yscale = await page.evaluate('view._runtime.scales.y.value.domain()'); + const drag = (await page.evaluate(brush(specType, i, parent)))[0]; + assert[assertExtents[specType].x[i]](drag.values[0][0], xscale[0], `iter: ${i}`); + assert[assertExtents[specType].x[i]](drag.values[0][1], xscale[1], `iter: ${i}`); + assert[assertExtents[specType].y[i]](drag.values[1][0], yscale[0], `iter: ${i}`); + assert[assertExtents[specType].y[i]](drag.values[1][1], yscale[1], `iter: ${i}`); + await testRender(`${specType}_${i}`); + } + }); + } } + }); + } + + it('should work with geo intervals', async () => { + testRender = testRenderFn(page, `interval/translate`); + + await embed(geoSpec()); + const drag = await page.evaluate(brush('drag', 1)); + expect(drag).toHaveLength(13); + await testRender(`geo-0`); + + for (let i = 0; i < hits.translate.length; i++) { + const translate = await page.evaluate(brush('translate', i, null, true)); + expect(translate.length).toBeGreaterThan(0); + await testRender(`geo-${i + 1}`); } }); -} +}); diff --git a/test-runtime/util.ts b/test-runtime/util.ts index 192974f3a59..62c30db31aa 100644 --- a/test-runtime/util.ts +++ b/test-runtime/util.ts @@ -3,7 +3,7 @@ import {sync as mkdirp} from 'mkdirp'; import {Page} from 'puppeteer/lib/cjs/puppeteer/common/Page'; import {promisify} from 'util'; import {stringValue} from 'vega-util'; -import {SelectionResolution, SelectionType} from '../src/selection'; +import {IntervalSelectionConfigWithoutType, SelectionResolution, SelectionType} from '../src/selection'; import {NormalizedLayerSpec, NormalizedUnitSpec, TopLevelSpec} from '../src/spec'; const generate = process.env.VL_GENERATE_TESTS; @@ -107,6 +107,14 @@ export const hits = { } }; +const config = { + // reduce changes in generated SVGs + aria: false, + + // A lot of magic numbers in this file use the old step = 21 + view: {discreteWidth: {step: 21}, discreteHeight: {step: 21}} +}; + function base(iter: number, selDef: any, opts: any = {}): NormalizedUnitSpec | NormalizedLayerSpec { const data = {values: opts.values ?? tuples}; const x = {field: 'a', type: 'quantitative', ...opts.x}; @@ -160,13 +168,6 @@ function base(iter: number, selDef: any, opts: any = {}): NormalizedUnitSpec | N export function spec(compose: ComposeType, iter: number, sel: any, opts: any = {}): TopLevelSpec { const {data, ...specification} = base(iter, sel, opts); const resolve = opts.resolve; - const config = { - // reduce changes in generated SVGs - aria: false, - - // A lot of magic numbers in this file use the old step = 21 - view: {discreteWidth: {step: 21}, discreteHeight: {step: 21}} - }; switch (compose) { case 'unit': return {data, ...specification, config} as TopLevelSpec; @@ -189,6 +190,65 @@ export function spec(compose: ComposeType, iter: number, sel: any, opts: any = { } } +export function geoSpec(selDef?: IntervalSelectionConfigWithoutType): TopLevelSpec { + return { + width: 500, + height: 300, + projection: {type: 'albersUsa'}, + config, + data: { + values: [ + {latitude: 31.95376472, longitude: -89.23450472}, + {latitude: 30.68586111, longitude: -95.01792778}, + {latitude: 38.94574889, longitude: -104.5698933}, + {latitude: 42.74134667, longitude: -78.05208056}, + {latitude: 30.6880125, longitude: -81.90594389}, + {latitude: 34.49166667, longitude: -88.20111111}, + {latitude: 32.85048667, longitude: -86.61145333}, + {latitude: 43.08751, longitude: -88.17786917}, + {latitude: 40.67331278, longitude: -80.64140639}, + {latitude: 40.44725889, longitude: -92.22696056}, + {latitude: 33.93011222, longitude: -89.34285194}, + {latitude: 46.88384889, longitude: -96.35089861}, + {latitude: 41.51961917, longitude: -87.40109333}, + {latitude: 31.42127556, longitude: -97.79696778}, + {latitude: 39.60416667, longitude: -116.0050597}, + {latitude: 32.46047167, longitude: -85.68003611}, + {latitude: 41.98934083, longitude: -88.10124278}, + {latitude: 48.88434111, longitude: -99.62087694}, + {latitude: 33.53456583, longitude: -89.31256917}, + {latitude: 41.43156583, longitude: -74.39191722}, + {latitude: 41.97602222, longitude: -114.6580911}, + {latitude: 41.30716667, longitude: -85.06433333}, + {latitude: 32.52883861, longitude: -94.97174556}, + {latitude: 42.57450861, longitude: -84.81143139}, + {latitude: 41.11668056, longitude: -98.05033639}, + {latitude: 32.52943944, longitude: -86.32822139}, + {latitude: 48.30079861, longitude: -102.4063514}, + {latitude: 40.65138528, longitude: -98.07978667}, + {latitude: 32.76124611, longitude: -89.53007139}, + {latitude: 32.11931306, longitude: -88.1274625} + ] + }, + mark: 'circle', + params: [ + { + name: 'sel', + select: {type: 'interval', ...selDef} + } + ], + encoding: { + longitude: {field: 'longitude', type: 'quantitative'}, + latitude: {field: 'latitude', type: 'quantitative'}, + color: { + condition: {param: 'sel', empty: false, value: 'goldenrod'}, + value: 'steelblue' + }, + size: {value: 10} + } + }; +} + export function unitNameRegex(specType: ComposeType, idx: number) { const name = UNIT_NAMES[specType][idx].replace('child_', ''); return new RegExp(`child(.*?)_${name}`); diff --git a/test-runtime/zoom.test.ts b/test-runtime/zoom.test.ts index 4ae6169ef44..f823ec3ba01 100644 --- a/test-runtime/zoom.test.ts +++ b/test-runtime/zoom.test.ts @@ -1,7 +1,18 @@ /* eslint-disable jest/expect-expect */ import {assert} from 'chai'; -import {bound, brush, compositeTypes, embedFn, parentSelector, spec, testRenderFn, tuples, unbound} from './util'; +import { + bound, + brush, + compositeTypes, + embedFn, + geoSpec, + parentSelector, + spec, + testRenderFn, + tuples, + unbound +} from './util'; const hits = { zoom: [9, 23], bins: [8, 2] @@ -16,140 +27,115 @@ function zoom(key: string, idx: number, direction: InOut, parent?: string, targe return `zoom(${hits[key][idx]}, ${delta}, ${parent}, ${targetBrush})`; } -const cmp = (a: number, b: number) => a - b; +describe('Zoom interval selections at runtime', () => { + let page: Page; + let embed: (specification: TopLevelSpec) => Promise; + let testRender: (filename: string) => Promise; -for (const bind of [bound, unbound]) { - describe(`Zoom ${bind} interval selections at runtime`, () => { - let page: Page; - let embed: (specification: TopLevelSpec) => Promise; - let testRender: (filename: string) => Promise; - - beforeAll(async () => { - page = await (global as any).__BROWSER__.newPage(); - embed = embedFn(page); - testRender = testRenderFn(page, `interval/zoom/${bind}`); - await page.goto('http://0.0.0.0:8000/test-runtime/'); - }); - - afterAll(async () => { - await page.close(); - }); + beforeAll(async () => { + page = await (global as any).__BROWSER__.newPage(); + embed = embedFn(page); + await page.goto('http://0.0.0.0:8000/test-runtime/'); + }); - const type = 'interval'; - const binding = bind === bound ? {bind: 'scales'} : {}; + afterAll(async () => { + await page.close(); + }); - const assertExtent = { - in: ['isAtLeast', 'isAtMost'], - out: ['isAtMost', 'isAtLeast'] - }; + for (const bind of [bound, unbound]) { + describe(`Zoom ${bind} interval selections at runtime`, () => { + beforeAll(() => { + testRender = testRenderFn(page, `interval/zoom/${bind}`); + }); - async function setup(brushKey: string, idx: number, encodings: string[], parent?: string) { - const inOut: InOut = idx % 2 ? 'out' : 'in'; - let xold: number[]; - let yold: number[]; + const type = 'interval'; + const binding = bind === bound ? {bind: 'scales'} : {}; + const cmp = (a: number, b: number) => a - b; + + const assertExtent = { + in: ['isAtLeast', 'isAtMost'], + out: ['isAtMost', 'isAtLeast'] + }; + + async function setup(brushKey: string, idx: number, encodings: string[], parent?: string) { + const inOut: InOut = idx % 2 ? 'out' : 'in'; + let xold: number[]; + let yold: number[]; + + if (bind === unbound) { + const drag = (await page.evaluate(brush(brushKey, idx, parent)))[0]; + xold = drag.values[0].sort(cmp); + yold = encodings.includes('y') ? drag.values[encodings.indexOf('x') + 1].sort(cmp) : null; + } else { + xold = JSON.parse((await page.evaluate('JSON.stringify(view._runtime.scales.x.value.domain())')) as string); + yold = (await page.evaluate('view._runtime.scales.y.value.domain()')) as number[]; + } - if (bind === unbound) { - const drag = (await page.evaluate(brush(brushKey, idx, parent)))[0]; - xold = drag.values[0].sort(cmp); - yold = encodings.includes('y') ? drag.values[encodings.indexOf('x') + 1].sort(cmp) : null; - } else { - xold = JSON.parse((await page.evaluate('JSON.stringify(view._runtime.scales.x.value.domain())')) as string); - yold = (await page.evaluate('view._runtime.scales.y.value.domain()')) as number[]; + return {inOut, xold, yold}; } - return {inOut, xold, yold}; - } + it('should zoom in and out', async () => { + for (let i = 0; i < hits.zoom.length; i++) { + await embed(spec('unit', i, {type, ...binding})); + const {inOut, xold, yold} = await setup('drag', i, ['x', 'y']); + await testRender(`${inOut}-0`); - it('should zoom in and out', async () => { - for (let i = 0; i < hits.zoom.length; i++) { - await embed(spec('unit', i, {type, ...binding})); - const {inOut, xold, yold} = await setup('drag', i, ['x', 'y']); - await testRender(`${inOut}-0`); - - const zoomed = (await page.evaluate(zoom('zoom', i, inOut, null, bind === unbound)))[0]; - const xnew = zoomed.values[0].sort(cmp); - const ynew = zoomed.values[1].sort(cmp); - await testRender(`${inOut}-1`); - assert[assertExtent[inOut][0]](xnew[0], xold[0]); - assert[assertExtent[inOut][1]](xnew[1], xold[1]); - assert[assertExtent[inOut][0]](ynew[0], yold[0]); - assert[assertExtent[inOut][1]](ynew[1], yold[1]); - } - }); + const zoomed = (await page.evaluate(zoom('zoom', i, inOut, null, bind === unbound)))[0]; + const xnew = zoomed.values[0].sort(cmp); + const ynew = zoomed.values[1].sort(cmp); + await testRender(`${inOut}-1`); + assert[assertExtent[inOut][0]](xnew[0], xold[0]); + assert[assertExtent[inOut][1]](xnew[1], xold[1]); + assert[assertExtent[inOut][0]](ynew[0], yold[0]); + assert[assertExtent[inOut][1]](ynew[1], yold[1]); + } + }); - it('should work with binned domains', async () => { - for (let i = 0; i < hits.bins.length; i++) { - const encodings = ['y']; - await embed( - spec( - 'unit', - 1, - {type, ...binding, encodings}, - { - x: {aggregate: 'count', type: 'quantitative'}, - y: {bin: true}, - color: {value: 'steelblue', field: null, type: null} - } - ) - ); + it('should work with binned domains', async () => { + for (let i = 0; i < hits.bins.length; i++) { + const encodings = ['y']; + await embed( + spec( + 'unit', + 1, + {type, ...binding, encodings}, + { + x: {aggregate: 'count', type: 'quantitative'}, + y: {bin: true}, + color: {value: 'steelblue', field: null, type: null} + } + ) + ); - const {inOut, yold} = await setup('bins', i, encodings); - await testRender(`bins_${inOut}-0`); + const {inOut, yold} = await setup('bins', i, encodings); + await testRender(`bins_${inOut}-0`); - const zoomed = (await page.evaluate(zoom('bins', i, inOut, null, bind === unbound)))[0]; - const ynew = zoomed.values[0].sort(cmp); - assert[assertExtent[inOut][0]](ynew[0], yold[0]); - assert[assertExtent[inOut][1]](ynew[1], yold[1]); - await testRender(`bins_${inOut}-1`); - } - }); - - it('should work with temporal domains', async () => { - const values = tuples.map(d => ({...d, a: new Date(2017, d.a)})); - const encodings = ['x']; + const zoomed = (await page.evaluate(zoom('bins', i, inOut, null, bind === unbound)))[0]; + const ynew = zoomed.values[0].sort(cmp); + assert[assertExtent[inOut][0]](ynew[0], yold[0]); + assert[assertExtent[inOut][1]](ynew[1], yold[1]); + await testRender(`bins_${inOut}-1`); + } + }); - for (let i = 0; i < hits.zoom.length; i++) { - await embed(spec('unit', i, {type, ...binding, encodings}, {values, x: {type: 'temporal'}})); - const {inOut, xold} = await setup('drag', i, encodings); - await testRender(`temporal_${inOut}-0`); + it('should work with temporal domains', async () => { + const values = tuples.map(d => ({...d, a: new Date(2017, d.a)})); + const encodings = ['x']; - const zoomed = (await page.evaluate(zoom('zoom', i, inOut, null, bind === unbound)))[0]; - const xnew = zoomed.values[0].sort(cmp); - assert[assertExtent[inOut][0]](+xnew[0], +new Date(xold[0])); - assert[assertExtent[inOut][1]](+xnew[1], +new Date(xold[1])); - await testRender(`temporal_${inOut}-1`); - } - }); + for (let i = 0; i < hits.zoom.length; i++) { + await embed(spec('unit', i, {type, ...binding, encodings}, {values, x: {type: 'temporal'}})); + const {inOut, xold} = await setup('drag', i, encodings); + await testRender(`temporal_${inOut}-0`); - it('should work with log/pow scales', async () => { - for (let i = 0; i < hits.zoom.length; i++) { - await embed( - spec( - 'unit', - i, - {type, ...binding}, - { - x: {scale: {type: 'pow', exponent: 1.5}}, - y: {scale: {type: 'log'}} - } - ) - ); - const {inOut, xold, yold} = await setup('drag', i, ['x', 'y']); - await testRender(`logpow_${inOut}-0`); - - const zoomed = (await page.evaluate(zoom('zoom', i, inOut, null, bind === unbound)))[0]; - const xnew = zoomed.values[0].sort(cmp); - const ynew = zoomed.values[1].sort(cmp); - assert[assertExtent[inOut][0]](xnew[0], xold[0]); - assert[assertExtent[inOut][1]](xnew[1], xold[1]); - assert[assertExtent[inOut][0]](ynew[0], yold[0]); - assert[assertExtent[inOut][1]](ynew[1], yold[1]); - await testRender(`logpow_${inOut}-1`); - } - }); + const zoomed = (await page.evaluate(zoom('zoom', i, inOut, null, bind === unbound)))[0]; + const xnew = zoomed.values[0].sort(cmp); + assert[assertExtent[inOut][0]](+xnew[0], +new Date(xold[0])); + assert[assertExtent[inOut][1]](+xnew[1], +new Date(xold[1])); + await testRender(`temporal_${inOut}-1`); + } + }); - if (bind === unbound) { - it('should work with ordinal/nominal domains', async () => { + it('should work with log/pow scales', async () => { for (let i = 0; i < hits.zoom.length; i++) { await embed( spec( @@ -157,47 +143,91 @@ for (const bind of [bound, unbound]) { i, {type, ...binding}, { - x: {type: 'ordinal'}, - y: {type: 'nominal'} + x: {scale: {type: 'pow', exponent: 1.5}}, + y: {scale: {type: 'log'}} } ) ); const {inOut, xold, yold} = await setup('drag', i, ['x', 'y']); - await testRender(`ord_${inOut}-0`); + await testRender(`logpow_${inOut}-0`); const zoomed = (await page.evaluate(zoom('zoom', i, inOut, null, bind === unbound)))[0]; const xnew = zoomed.values[0].sort(cmp); const ynew = zoomed.values[1].sort(cmp); - - if (inOut === 'in') { - expect(xnew.length).toBeLessThanOrEqual(xold.length); - expect(ynew.length).toBeLessThanOrEqual(yold.length); - } else { - expect(xnew.length).toBeGreaterThanOrEqual(xold.length); - expect(ynew.length).toBeGreaterThanOrEqual(yold.length); - } - - await testRender(`ord_${inOut}-1`); + assert[assertExtent[inOut][0]](xnew[0], xold[0]); + assert[assertExtent[inOut][1]](xnew[1], xold[1]); + assert[assertExtent[inOut][0]](ynew[0], yold[0]); + assert[assertExtent[inOut][1]](ynew[1], yold[1]); + await testRender(`logpow_${inOut}-1`); } }); - } else { - for (const specType of compositeTypes) { - it(`should work with shared scales in ${specType} views`, async () => { - for (let i = 0; i < hits.bins.length; i++) { - await embed(spec(specType, 0, {type, ...binding}, {resolve: {scale: {x: 'shared', y: 'shared'}}})); - const parent = parentSelector(specType, i); - const {inOut, xold, yold} = await setup(specType, i, ['x', 'y'], parent); - const zoomed = (await page.evaluate(zoom('bins', i, inOut, null, bind === unbound)))[0]; + + if (bind === unbound) { + it('should work with ordinal/nominal domains', async () => { + for (let i = 0; i < hits.zoom.length; i++) { + await embed( + spec( + 'unit', + i, + {type, ...binding}, + { + x: {type: 'ordinal'}, + y: {type: 'nominal'} + } + ) + ); + const {inOut, xold, yold} = await setup('drag', i, ['x', 'y']); + await testRender(`ord_${inOut}-0`); + + const zoomed = (await page.evaluate(zoom('zoom', i, inOut, null, bind === unbound)))[0]; const xnew = zoomed.values[0].sort(cmp); const ynew = zoomed.values[1].sort(cmp); - assert[assertExtent[inOut][0]](xnew[0], xold[0]); - assert[assertExtent[inOut][1]](xnew[1], xold[1]); - assert[assertExtent[inOut][0]](ynew[0], yold[0]); - assert[assertExtent[inOut][1]](ynew[1], yold[1]); - await testRender(`${specType}_${inOut}`); + + if (inOut === 'in') { + expect(xnew.length).toBeLessThanOrEqual(xold.length); + expect(ynew.length).toBeLessThanOrEqual(yold.length); + } else { + expect(xnew.length).toBeGreaterThanOrEqual(xold.length); + expect(ynew.length).toBeGreaterThanOrEqual(yold.length); + } + + await testRender(`ord_${inOut}-1`); } }); + } else { + for (const specType of compositeTypes) { + it(`should work with shared scales in ${specType} views`, async () => { + for (let i = 0; i < hits.bins.length; i++) { + await embed(spec(specType, 0, {type, ...binding}, {resolve: {scale: {x: 'shared', y: 'shared'}}})); + const parent = parentSelector(specType, i); + const {inOut, xold, yold} = await setup(specType, i, ['x', 'y'], parent); + const zoomed = (await page.evaluate(zoom('bins', i, inOut, null, bind === unbound)))[0]; + const xnew = zoomed.values[0].sort(cmp); + const ynew = zoomed.values[1].sort(cmp); + assert[assertExtent[inOut][0]](xnew[0], xold[0]); + assert[assertExtent[inOut][1]](xnew[1], xold[1]); + assert[assertExtent[inOut][0]](ynew[0], yold[0]); + assert[assertExtent[inOut][1]](ynew[1], yold[1]); + await testRender(`${specType}_${inOut}`); + } + }); + } } + }); + } + + it('should work with geo intervals', async () => { + testRender = testRenderFn(page, `interval/zoom`); + + await embed(geoSpec()); + const drag = await page.evaluate(brush('drag', 1)); + expect(drag).toHaveLength(13); + await testRender(`geo-0`); + + for (let i = 0; i < hits.zoom.length; i++) { + const zoomed = await page.evaluate(zoom('zoom', i, i % 2 ? 'out' : 'in', null, true)); + expect(zoomed.length).toBeGreaterThan(0); + await testRender(`geo-${i + 1}`); } }); -} +}); diff --git a/test/compile/model.test.ts b/test/compile/model.test.ts index 1f919833d37..7389cb19153 100644 --- a/test/compile/model.test.ts +++ b/test/compile/model.test.ts @@ -32,7 +32,7 @@ describe('Model', () => { mark: 'point' }); - expect(model.assembleGroupStyle()).toBeUndefined(); + expect(model.assembleGroupStyle()).toBe('view'); }); it('returns cell by default for cartesian plots', () => { diff --git a/test/compile/selection/interval.test.ts b/test/compile/selection/interval.test.ts index 1b8841a882d..c626cd0784b 100644 --- a/test/compile/selection/interval.test.ts +++ b/test/compile/selection/interval.test.ts @@ -1,391 +1,517 @@ import {parseSelector} from 'vega-event-selector'; import {assembleUnitSelectionSignals} from '../../../src/compile/selection/assemble'; -import interval from '../../../src/compile/selection/interval'; +import interval, {GEO_INIT_TICK} from '../../../src/compile/selection/interval'; import {parseUnitSelection} from '../../../src/compile/selection/parse'; -import {parseUnitModel} from '../../util'; +import {parseUnitModel, parseUnitModelWithScale, parseUnitModelWithScaleAndLayoutSize} from '../../util'; describe('Interval Selections', () => { - const model = parseUnitModel({ - mark: 'circle', - encoding: { - x: {field: 'Horsepower', type: 'quantitative'}, - y: {field: 'Miles-per-Gallon', type: 'quantitative'}, - color: {field: 'Origin', type: 'nominal'} - } - }); - model.parseScale(); - - const selCmpts = (model.component.selection = parseUnitSelection(model, [ - { - name: 'one', - select: {type: 'interval', encodings: ['x'], clear: false, translate: false, zoom: false} - }, - { - name: 'two', - select: { - type: 'interval', - encodings: ['y'], - clear: false, - translate: false, - zoom: false + describe('Scaled intervals', () => { + const model = parseUnitModelWithScale({ + mark: 'circle', + encoding: { + x: {field: 'Horsepower', type: 'quantitative'}, + y: {field: 'Miles-per-Gallon', type: 'quantitative'}, + color: {field: 'Origin', type: 'nominal'} + } + }); + + const selCmpts = (model.component.selection = parseUnitSelection(model, [ + { + name: 'one', + select: {type: 'interval', encodings: ['x'], clear: false, translate: false, zoom: false} }, - bind: 'scales' - }, - { - name: 'thr-ee', - select: { - type: 'interval', - on: '[mousedown, mouseup] > mousemove, [keydown, keyup] > keypress', - clear: false, - translate: false, - zoom: false, - resolve: 'intersect', - mark: { - fill: 'red', - fillOpacity: 0.75, - stroke: 'black', - strokeWidth: 4, - strokeDash: [10, 5], - strokeDashOffset: 3, - strokeOpacity: 0.25 + { + name: 'two', + select: { + type: 'interval', + encodings: ['y'], + clear: false, + translate: false, + zoom: false + }, + bind: 'scales' + }, + { + name: 'thr-ee', + select: { + type: 'interval', + on: '[mousedown, mouseup] > mousemove, [keydown, keyup] > keypress', + clear: false, + translate: false, + zoom: false, + resolve: 'intersect', + mark: { + fill: 'red', + fillOpacity: 0.75, + stroke: 'black', + strokeWidth: 4, + strokeDash: [10, 5], + strokeDashOffset: 3, + strokeOpacity: 0.25 + } } - } - }, - { - name: 'four', - value: {x: [50, 70]}, - select: { - type: 'interval', - encodings: ['x'], - clear: false, - translate: false, - zoom: false - } - }, - { - name: 'five', - value: {x: [50, 60], y: [23, 54]}, - select: { - type: 'interval', - clear: false, - translate: false, - zoom: false - } - }, - { - name: 'six', - value: { - x: [ - {year: 2000, month: 10, date: 5}, - {year: 2001, month: 1, date: 13} - ] }, - select: { - type: 'interval', - clear: false, - translate: false, - zoom: false, - encodings: ['x'] + { + name: 'four', + value: {x: [50, 70]}, + select: { + type: 'interval', + encodings: ['x'], + clear: false, + translate: false, + zoom: false + } + }, + { + name: 'five', + value: {x: [50, 60], y: [23, 54]}, + select: { + type: 'interval', + clear: false, + translate: false, + zoom: false + } + }, + { + name: 'six', + value: { + x: [ + {year: 2000, month: 10, date: 5}, + {year: 2001, month: 1, date: 13} + ] + }, + select: { + type: 'interval', + clear: false, + translate: false, + zoom: false, + encodings: ['x'] + } } - } - ])); + ])); - describe('Tuple Signals', () => { - it('builds projection signals', () => { - const oneSg = interval.signals(model, selCmpts['one'], []); - expect(oneSg).toEqual( - expect.arrayContaining([ - { - name: 'one_x', - value: [], - on: [ - { - events: parseSelector('mousedown', 'scope')[0], - update: '[x(unit), x(unit)]' - }, - { - events: parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')[0], - update: '[one_x[0], clamp(x(unit), 0, width)]' - }, - { - events: {signal: 'one_scale_trigger'}, - update: '[scale("x", one_Horsepower[0]), scale("x", one_Horsepower[1])]' - } - ] - }, - { - name: 'one_Horsepower', - on: [ - { - events: {signal: 'one_x'}, - update: 'one_x[0] === one_x[1] ? null : invert("x", one_x)' - } - ] - }, - { - name: 'one_scale_trigger', - value: {}, - on: [ - { - events: [{scale: 'x'}], - update: - '(!isArray(one_Horsepower) || (+invert("x", one_x)[0] === +one_Horsepower[0] && +invert("x", one_x)[1] === +one_Horsepower[1])) ? one_scale_trigger : {}' - } - ] - } - ]) - ); + describe('Tuple Signals', () => { + it('builds projection signals', () => { + const oneSg = interval.signals(model, selCmpts['one'], []); + expect(oneSg).toEqual( + expect.arrayContaining([ + { + name: 'one_x', + value: [], + on: [ + { + events: parseSelector('mousedown', 'scope')[0], + update: '[x(unit), x(unit)]' + }, + { + events: parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')[0], + update: '[one_x[0], clamp(x(unit), 0, width)]' + }, + { + events: {signal: 'one_scale_trigger'}, + update: '[scale("x", one_Horsepower[0]), scale("x", one_Horsepower[1])]' + } + ] + }, + { + name: 'one_Horsepower', + on: [ + { + events: {signal: 'one_x'}, + update: 'one_x[0] === one_x[1] ? null : invert("x", one_x)' + } + ] + }, + { + name: 'one_scale_trigger', + value: {}, + on: [ + { + events: [{scale: 'x'}], + update: + '(!isArray(one_Horsepower) || (+invert("x", one_x)[0] === +one_Horsepower[0] && +invert("x", one_x)[1] === +one_Horsepower[1])) ? one_scale_trigger : {}' + } + ] + } + ]) + ); + + const twoSg = interval.signals(model, selCmpts['two'], []); + expect(twoSg).toContainEqual({ + name: 'two_Miles_per_Gallon', + on: [] + }); + + const threeSg = interval.signals(model, selCmpts['thr_ee'], []); + expect(threeSg).toEqual( + expect.arrayContaining([ + { + name: 'thr_ee_x', + value: [], + on: [ + { + events: parseSelector('mousedown', 'scope')[0], + update: '[x(unit), x(unit)]' + }, + { + events: parseSelector('[mousedown, mouseup] > mousemove', 'scope')[0], + update: '[thr_ee_x[0], clamp(x(unit), 0, width)]' + }, + { + events: parseSelector('keydown', 'scope')[0], + update: '[x(unit), x(unit)]' + }, + { + events: parseSelector('[keydown, keyup] > keypress', 'scope')[0], + update: '[thr_ee_x[0], clamp(x(unit), 0, width)]' + }, + { + events: {signal: 'thr_ee_scale_trigger'}, + update: '[scale("x", thr_ee_Horsepower[0]), scale("x", thr_ee_Horsepower[1])]' + } + ] + }, + { + name: 'thr_ee_Horsepower', + on: [ + { + events: {signal: 'thr_ee_x'}, + update: 'thr_ee_x[0] === thr_ee_x[1] ? null : invert("x", thr_ee_x)' + } + ] + }, + { + name: 'thr_ee_y', + value: [], + on: [ + { + events: parseSelector('mousedown', 'scope')[0], + update: '[y(unit), y(unit)]' + }, + { + events: parseSelector('[mousedown, mouseup] > mousemove', 'scope')[0], + update: '[thr_ee_y[0], clamp(y(unit), 0, height)]' + }, + { + events: parseSelector('keydown', 'scope')[0], + update: '[y(unit), y(unit)]' + }, + { + events: parseSelector('[keydown, keyup] > keypress', 'scope')[0], + update: '[thr_ee_y[0], clamp(y(unit), 0, height)]' + }, + { + events: {signal: 'thr_ee_scale_trigger'}, + update: '[scale("y", thr_ee_Miles_per_Gallon[0]), scale("y", thr_ee_Miles_per_Gallon[1])]' + } + ] + }, + { + name: 'thr_ee_Miles_per_Gallon', + on: [ + { + events: {signal: 'thr_ee_y'}, + update: 'thr_ee_y[0] === thr_ee_y[1] ? null : invert("y", thr_ee_y)' + } + ] + }, + { + name: 'thr_ee_scale_trigger', + value: {}, + on: [ + { + events: [{scale: 'x'}, {scale: 'y'}], + update: + '(!isArray(thr_ee_Horsepower) || (+invert("x", thr_ee_x)[0] === +thr_ee_Horsepower[0] && +invert("x", thr_ee_x)[1] === +thr_ee_Horsepower[1])) && (!isArray(thr_ee_Miles_per_Gallon) || (+invert("y", thr_ee_y)[0] === +thr_ee_Miles_per_Gallon[0] && +invert("y", thr_ee_y)[1] === +thr_ee_Miles_per_Gallon[1])) ? thr_ee_scale_trigger : {}' + } + ] + } + ]) + ); - const twoSg = interval.signals(model, selCmpts['two'], []); - expect(twoSg).toContainEqual({ - name: 'two_Miles_per_Gallon', - on: [] + const fourSg = interval.signals(model, selCmpts['four'], []); + expect(fourSg).toEqual( + expect.arrayContaining([ + { + name: 'four_x', + init: '[scale("x", 50), scale("x", 70)]', + on: [ + { + events: parseSelector('mousedown', 'scope')[0], + update: '[x(unit), x(unit)]' + }, + { + events: parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')[0], + update: '[four_x[0], clamp(x(unit), 0, width)]' + }, + { + events: {signal: 'four_scale_trigger'}, + update: '[scale("x", four_Horsepower[0]), scale("x", four_Horsepower[1])]' + } + ] + }, + { + name: 'four_Horsepower', + init: '[50, 70]', + on: [ + { + events: {signal: 'four_x'}, + update: 'four_x[0] === four_x[1] ? null : invert("x", four_x)' + } + ] + }, + { + name: 'four_scale_trigger', + value: {}, + on: [ + { + events: [{scale: 'x'}], + update: + '(!isArray(four_Horsepower) || (+invert("x", four_x)[0] === +four_Horsepower[0] && +invert("x", four_x)[1] === +four_Horsepower[1])) ? four_scale_trigger : {}' + } + ] + } + ]) + ); + + const fiveSg = interval.signals(model, selCmpts['five'], []); + expect(fiveSg).toEqual( + expect.arrayContaining([ + { + name: 'five_x', + init: '[scale("x", 50), scale("x", 60)]', + on: [ + { + events: parseSelector('mousedown', 'scope')[0], + update: '[x(unit), x(unit)]' + }, + { + events: parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')[0], + update: '[five_x[0], clamp(x(unit), 0, width)]' + }, + { + events: {signal: 'five_scale_trigger'}, + update: '[scale("x", five_Horsepower[0]), scale("x", five_Horsepower[1])]' + } + ] + }, + { + name: 'five_Horsepower', + init: '[50, 60]', + on: [ + { + events: {signal: 'five_x'}, + update: 'five_x[0] === five_x[1] ? null : invert("x", five_x)' + } + ] + }, + { + name: 'five_y', + init: '[scale("y", 23), scale("y", 54)]', + on: [ + { + events: parseSelector('mousedown', 'scope')[0], + update: '[y(unit), y(unit)]' + }, + { + events: parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')[0], + update: '[five_y[0], clamp(y(unit), 0, height)]' + }, + { + events: {signal: 'five_scale_trigger'}, + update: '[scale("y", five_Miles_per_Gallon[0]), scale("y", five_Miles_per_Gallon[1])]' + } + ] + }, + { + name: 'five_Miles_per_Gallon', + init: '[23, 54]', + on: [ + { + events: {signal: 'five_y'}, + update: 'five_y[0] === five_y[1] ? null : invert("y", five_y)' + } + ] + }, + { + name: 'five_scale_trigger', + value: {}, + on: [ + { + events: [{scale: 'x'}, {scale: 'y'}], + update: + '(!isArray(five_Horsepower) || (+invert("x", five_x)[0] === +five_Horsepower[0] && +invert("x", five_x)[1] === +five_Horsepower[1])) && (!isArray(five_Miles_per_Gallon) || (+invert("y", five_y)[0] === +five_Miles_per_Gallon[0] && +invert("y", five_y)[1] === +five_Miles_per_Gallon[1])) ? five_scale_trigger : {}' + } + ] + } + ]) + ); + + const sixSg = interval.signals(model, selCmpts['six'], []); + expect(sixSg).toEqual( + expect.arrayContaining([ + { + name: 'six_x', + init: '[scale("x", datetime(2000, 9, 5, 0, 0, 0, 0)), scale("x", datetime(2001, 0, 13, 0, 0, 0, 0))]', + on: [ + { + events: parseSelector('mousedown', 'scope')[0], + update: '[x(unit), x(unit)]' + }, + { + events: parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')[0], + update: '[six_x[0], clamp(x(unit), 0, width)]' + }, + { + events: {signal: 'six_scale_trigger'}, + update: '[scale("x", six_Horsepower[0]), scale("x", six_Horsepower[1])]' + } + ] + }, + { + name: 'six_Horsepower', + init: '[datetime(2000, 9, 5, 0, 0, 0, 0), datetime(2001, 0, 13, 0, 0, 0, 0)]', + on: [ + { + events: {signal: 'six_x'}, + update: 'six_x[0] === six_x[1] ? null : invert("x", six_x)' + } + ] + }, + { + name: 'six_scale_trigger', + value: {}, + on: [ + { + events: [{scale: 'x'}], + update: + '(!isArray(six_Horsepower) || (+invert("x", six_x)[0] === +six_Horsepower[0] && +invert("x", six_x)[1] === +six_Horsepower[1])) ? six_scale_trigger : {}' + } + ] + } + ]) + ); }); - const threeSg = interval.signals(model, selCmpts['thr_ee'], []); - expect(threeSg).toEqual( - expect.arrayContaining([ - { - name: 'thr_ee_x', - value: [], - on: [ - { - events: parseSelector('mousedown', 'scope')[0], - update: '[x(unit), x(unit)]' - }, - { - events: parseSelector('[mousedown, mouseup] > mousemove', 'scope')[0], - update: '[thr_ee_x[0], clamp(x(unit), 0, width)]' - }, - { - events: parseSelector('keydown', 'scope')[0], - update: '[x(unit), x(unit)]' - }, - { - events: parseSelector('[keydown, keyup] > keypress', 'scope')[0], - update: '[thr_ee_x[0], clamp(x(unit), 0, width)]' - }, - { - events: {signal: 'thr_ee_scale_trigger'}, - update: '[scale("x", thr_ee_Horsepower[0]), scale("x", thr_ee_Horsepower[1])]' - } - ] - }, - { - name: 'thr_ee_Horsepower', - on: [ - { - events: {signal: 'thr_ee_x'}, - update: 'thr_ee_x[0] === thr_ee_x[1] ? null : invert("x", thr_ee_x)' - } - ] - }, - { - name: 'thr_ee_y', - value: [], - on: [ - { - events: parseSelector('mousedown', 'scope')[0], - update: '[y(unit), y(unit)]' - }, - { - events: parseSelector('[mousedown, mouseup] > mousemove', 'scope')[0], - update: '[thr_ee_y[0], clamp(y(unit), 0, height)]' - }, - { - events: parseSelector('keydown', 'scope')[0], - update: '[y(unit), y(unit)]' - }, - { - events: parseSelector('[keydown, keyup] > keypress', 'scope')[0], - update: '[thr_ee_y[0], clamp(y(unit), 0, height)]' - }, - { - events: {signal: 'thr_ee_scale_trigger'}, - update: '[scale("y", thr_ee_Miles_per_Gallon[0]), scale("y", thr_ee_Miles_per_Gallon[1])]' - } - ] - }, - { - name: 'thr_ee_Miles_per_Gallon', - on: [ - { - events: {signal: 'thr_ee_y'}, - update: 'thr_ee_y[0] === thr_ee_y[1] ? null : invert("y", thr_ee_y)' - } - ] - }, - { - name: 'thr_ee_scale_trigger', - value: {}, - on: [ - { - events: [{scale: 'x'}, {scale: 'y'}], - update: - '(!isArray(thr_ee_Horsepower) || (+invert("x", thr_ee_x)[0] === +thr_ee_Horsepower[0] && +invert("x", thr_ee_x)[1] === +thr_ee_Horsepower[1])) && (!isArray(thr_ee_Miles_per_Gallon) || (+invert("y", thr_ee_y)[0] === +thr_ee_Miles_per_Gallon[0] && +invert("y", thr_ee_y)[1] === +thr_ee_Miles_per_Gallon[1])) ? thr_ee_scale_trigger : {}' - } - ] - } - ]) - ); + it('builds trigger signals', () => { + const oneSg = interval.signals(model, selCmpts['one'], []); + expect(oneSg).toContainEqual({ + name: 'one_tuple', + on: [ + { + events: [{signal: 'one_Horsepower'}], + update: 'one_Horsepower ? {unit: "", fields: one_tuple_fields, values: [one_Horsepower]} : null' + } + ] + }); - const fourSg = interval.signals(model, selCmpts['four'], []); - expect(fourSg).toEqual( - expect.arrayContaining([ - { - name: 'four_x', - init: '[scale("x", 50), scale("x", 70)]', - on: [ - { - events: parseSelector('mousedown', 'scope')[0], - update: '[x(unit), x(unit)]' - }, - { - events: parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')[0], - update: '[four_x[0], clamp(x(unit), 0, width)]' - }, - { - events: {signal: 'four_scale_trigger'}, - update: '[scale("x", four_Horsepower[0]), scale("x", four_Horsepower[1])]' - } - ] - }, - { - name: 'four_Horsepower', - init: '[50, 70]', - on: [ - { - events: {signal: 'four_x'}, - update: 'four_x[0] === four_x[1] ? null : invert("x", four_x)' - } - ] - }, - { - name: 'four_scale_trigger', - value: {}, - on: [ - { - events: [{scale: 'x'}], - update: - '(!isArray(four_Horsepower) || (+invert("x", four_x)[0] === +four_Horsepower[0] && +invert("x", four_x)[1] === +four_Horsepower[1])) ? four_scale_trigger : {}' - } - ] + const twoSg = interval.signals(model, selCmpts['two'], []); + expect(twoSg).toContainEqual({ + name: 'two_tuple', + on: [ + { + events: [{signal: 'two_Miles_per_Gallon'}], + update: + 'two_Miles_per_Gallon ? {unit: "", fields: two_tuple_fields, values: [two_Miles_per_Gallon]} : null' + } + ] + }); + + const threeSg = interval.signals(model, selCmpts['thr_ee'], []); + expect(threeSg).toContainEqual({ + name: 'thr_ee_tuple', + on: [ + { + events: [{signal: 'thr_ee_Horsepower || thr_ee_Miles_per_Gallon'}], + update: + 'thr_ee_Horsepower && thr_ee_Miles_per_Gallon ? {unit: "", fields: thr_ee_tuple_fields, values: [thr_ee_Horsepower,thr_ee_Miles_per_Gallon]} : null' + } + ] + }); + + const fourSg = interval.signals(model, selCmpts['four'], []); + expect(fourSg).toContainEqual({ + name: 'four_tuple', + init: '{unit: "", fields: four_tuple_fields, values: [[50, 70]]}', + on: [ + { + events: [{signal: 'four_Horsepower'}], + update: 'four_Horsepower ? {unit: "", fields: four_tuple_fields, values: [four_Horsepower]} : null' + } + ] + }); + + const fiveSg = interval.signals(model, selCmpts['five'], []); + expect(fiveSg).toContainEqual({ + name: 'five_tuple', + init: '{unit: "", fields: five_tuple_fields, values: [[50, 60], [23, 54]]}', + on: [ + { + events: [{signal: 'five_Horsepower || five_Miles_per_Gallon'}], + update: + 'five_Horsepower && five_Miles_per_Gallon ? {unit: "", fields: five_tuple_fields, values: [five_Horsepower,five_Miles_per_Gallon]} : null' + } + ] + }); + }); + + it('namespaces signals when encoding/fields collide', () => { + const model2 = parseUnitModel({ + mark: 'circle', + encoding: { + x: {field: 'x', type: 'quantitative'}, + y: {field: 'y', type: 'quantitative'} } - ]) - ); + }); - const fiveSg = interval.signals(model, selCmpts['five'], []); - expect(fiveSg).toEqual( - expect.arrayContaining([ - { - name: 'five_x', - init: '[scale("x", 50), scale("x", 60)]', - on: [ - { - events: parseSelector('mousedown', 'scope')[0], - update: '[x(unit), x(unit)]' - }, - { - events: parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')[0], - update: '[five_x[0], clamp(x(unit), 0, width)]' - }, - { - events: {signal: 'five_scale_trigger'}, - update: '[scale("x", five_Horsepower[0]), scale("x", five_Horsepower[1])]' - } - ] - }, - { - name: 'five_Horsepower', - init: '[50, 60]', - on: [ - { - events: {signal: 'five_x'}, - update: 'five_x[0] === five_x[1] ? null : invert("x", five_x)' - } - ] - }, - { - name: 'five_y', - init: '[scale("y", 23), scale("y", 54)]', - on: [ - { - events: parseSelector('mousedown', 'scope')[0], - update: '[y(unit), y(unit)]' - }, - { - events: parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')[0], - update: '[five_y[0], clamp(y(unit), 0, height)]' - }, - { - events: {signal: 'five_scale_trigger'}, - update: '[scale("y", five_Miles_per_Gallon[0]), scale("y", five_Miles_per_Gallon[1])]' - } - ] - }, - { - name: 'five_Miles_per_Gallon', - init: '[23, 54]', - on: [ - { - events: {signal: 'five_y'}, - update: 'five_y[0] === five_y[1] ? null : invert("y", five_y)' - } - ] - }, + model2.parseScale(); + + const selCmpts2 = (model2.component.selection = parseUnitSelection(model2, [ { - name: 'five_scale_trigger', - value: {}, - on: [ - { - events: [{scale: 'x'}, {scale: 'y'}], - update: - '(!isArray(five_Horsepower) || (+invert("x", five_x)[0] === +five_Horsepower[0] && +invert("x", five_x)[1] === +five_Horsepower[1])) && (!isArray(five_Miles_per_Gallon) || (+invert("y", five_y)[0] === +five_Miles_per_Gallon[0] && +invert("y", five_y)[1] === +five_Miles_per_Gallon[1])) ? five_scale_trigger : {}' - } - ] + name: 'one', + select: { + type: 'interval', + encodings: ['x'], + translate: false, + zoom: false + } } - ]) - ); + ])); - const sixSg = interval.signals(model, selCmpts['six'], []); - expect(sixSg).toEqual( + const sg = interval.signals(model, selCmpts2['one'], []); + expect(sg[0].name).toBe('one_x_1'); + expect(sg[1].name).toBe('one_x'); + }); + }); + + it('builds modify signals', () => { + const signals = assembleUnitSelectionSignals(model, []); + expect(signals).toEqual( expect.arrayContaining([ { - name: 'six_x', - init: '[scale("x", datetime(2000, 9, 5, 0, 0, 0, 0)), scale("x", datetime(2001, 0, 13, 0, 0, 0, 0))]', + name: 'one_modify', on: [ { - events: parseSelector('mousedown', 'scope')[0], - update: '[x(unit), x(unit)]' - }, - { - events: parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')[0], - update: '[six_x[0], clamp(x(unit), 0, width)]' - }, - { - events: {signal: 'six_scale_trigger'}, - update: '[scale("x", six_Horsepower[0]), scale("x", six_Horsepower[1])]' + events: {signal: 'one_tuple'}, + update: `modify("one_store", one_tuple, true)` } ] }, { - name: 'six_Horsepower', - init: '[datetime(2000, 9, 5, 0, 0, 0, 0), datetime(2001, 0, 13, 0, 0, 0, 0)]', + name: 'two_modify', on: [ { - events: {signal: 'six_x'}, - update: 'six_x[0] === six_x[1] ? null : invert("x", six_x)' + events: {signal: 'two_tuple'}, + update: `modify("two_store", two_tuple, true)` } ] }, { - name: 'six_scale_trigger', - value: {}, + name: 'thr_ee_modify', on: [ { - events: [{scale: 'x'}], - update: - '(!isArray(six_Horsepower) || (+invert("x", six_x)[0] === +six_Horsepower[0] && +invert("x", six_x)[1] === +six_Horsepower[1])) ? six_scale_trigger : {}' + events: {signal: 'thr_ee_tuple'}, + update: `modify("thr_ee_store", thr_ee_tuple, {unit: ""})` } ] } @@ -393,446 +519,538 @@ describe('Interval Selections', () => { ); }); - it('builds trigger signals', () => { - const oneSg = interval.signals(model, selCmpts['one'], []); - expect(oneSg).toContainEqual({ - name: 'one_tuple', - on: [ - { - events: [{signal: 'one_Horsepower'}], - update: 'one_Horsepower ? {unit: "", fields: one_tuple_fields, values: [one_Horsepower]} : null' + it('builds brush mark', () => { + const marks: any[] = [{hello: 'world'}]; + expect(interval.marks(model, selCmpts['one'], marks)).toEqual([ + { + name: 'one_brush_bg', + type: 'rect', + clip: true, + encode: { + enter: { + fill: {value: '#333'}, + fillOpacity: {value: 0.125} + }, + update: { + x: [ + { + test: 'data("one_store").length && data("one_store")[0].unit === ""', + signal: 'one_x[0]' + }, + { + value: 0 + } + ], + y: [ + { + test: 'data("one_store").length && data("one_store")[0].unit === ""', + value: 0 + }, + { + value: 0 + } + ], + x2: [ + { + test: 'data("one_store").length && data("one_store")[0].unit === ""', + signal: 'one_x[1]' + }, + { + value: 0 + } + ], + y2: [ + { + test: 'data("one_store").length && data("one_store")[0].unit === ""', + field: { + group: 'height' + } + }, + { + value: 0 + } + ] + } } - ] - }); - - const twoSg = interval.signals(model, selCmpts['two'], []); - expect(twoSg).toContainEqual({ - name: 'two_tuple', - on: [ - { - events: [{signal: 'two_Miles_per_Gallon'}], - update: 'two_Miles_per_Gallon ? {unit: "", fields: two_tuple_fields, values: [two_Miles_per_Gallon]} : null' + }, + {hello: 'world'}, + { + name: 'one_brush', + type: 'rect', + clip: true, + encode: { + enter: { + fill: {value: 'transparent'} + }, + update: { + stroke: [ + { + test: 'one_x[0] !== one_x[1]', + value: 'white' + }, + { + value: null + } + ], + x: [ + { + test: 'data("one_store").length && data("one_store")[0].unit === ""', + signal: 'one_x[0]' + }, + { + value: 0 + } + ], + y: [ + { + test: 'data("one_store").length && data("one_store")[0].unit === ""', + value: 0 + }, + { + value: 0 + } + ], + x2: [ + { + test: 'data("one_store").length && data("one_store")[0].unit === ""', + signal: 'one_x[1]' + }, + { + value: 0 + } + ], + y2: [ + { + test: 'data("one_store").length && data("one_store")[0].unit === ""', + field: { + group: 'height' + } + }, + { + value: 0 + } + ] + } } - ] - }); + } + ]); - const threeSg = interval.signals(model, selCmpts['thr_ee'], []); - expect(threeSg).toContainEqual({ - name: 'thr_ee_tuple', - on: [ - { - events: [{signal: 'thr_ee_Horsepower || thr_ee_Miles_per_Gallon'}], - update: - 'thr_ee_Horsepower && thr_ee_Miles_per_Gallon ? {unit: "", fields: thr_ee_tuple_fields, values: [thr_ee_Horsepower,thr_ee_Miles_per_Gallon]} : null' - } - ] - }); + // Scale-bound interval selections should not add a brush mark. + expect(interval.marks(model, selCmpts['two'], marks)).toEqual(marks); - const fourSg = interval.signals(model, selCmpts['four'], []); - expect(fourSg).toContainEqual({ - name: 'four_tuple', - init: '{unit: "", fields: four_tuple_fields, values: [[50, 70]]}', - on: [ - { - events: [{signal: 'four_Horsepower'}], - update: 'four_Horsepower ? {unit: "", fields: four_tuple_fields, values: [four_Horsepower]} : null' + expect(interval.marks(model, selCmpts['thr_ee'], marks)).toEqual([ + { + name: 'thr_ee_brush_bg', + type: 'rect', + clip: true, + encode: { + enter: { + fill: {value: 'red'}, + fillOpacity: {value: 0.75} + }, + update: { + x: { + signal: 'thr_ee_x[0]' + }, + y: { + signal: 'thr_ee_y[0]' + }, + x2: { + signal: 'thr_ee_x[1]' + }, + y2: { + signal: 'thr_ee_y[1]' + } + } } - ] - }); - - const fiveSg = interval.signals(model, selCmpts['five'], []); - expect(fiveSg).toContainEqual({ - name: 'five_tuple', - init: '{unit: "", fields: five_tuple_fields, values: [[50, 60], [23, 54]]}', - on: [ - { - events: [{signal: 'five_Horsepower || five_Miles_per_Gallon'}], - update: - 'five_Horsepower && five_Miles_per_Gallon ? {unit: "", fields: five_tuple_fields, values: [five_Horsepower,five_Miles_per_Gallon]} : null' + }, + {hello: 'world'}, + { + name: 'thr_ee_brush', + type: 'rect', + clip: true, + encode: { + enter: { + fill: {value: 'transparent'} + }, + update: { + stroke: [ + { + test: 'thr_ee_x[0] !== thr_ee_x[1] && thr_ee_y[0] !== thr_ee_y[1]', + value: 'black' + }, + {value: null} + ], + strokeWidth: [ + { + test: 'thr_ee_x[0] !== thr_ee_x[1] && thr_ee_y[0] !== thr_ee_y[1]', + value: 4 + }, + {value: null} + ], + strokeDash: [ + { + test: 'thr_ee_x[0] !== thr_ee_x[1] && thr_ee_y[0] !== thr_ee_y[1]', + value: [10, 5] + }, + {value: null} + ], + strokeDashOffset: [ + { + test: 'thr_ee_x[0] !== thr_ee_x[1] && thr_ee_y[0] !== thr_ee_y[1]', + value: 3 + }, + {value: null} + ], + strokeOpacity: [ + { + test: 'thr_ee_x[0] !== thr_ee_x[1] && thr_ee_y[0] !== thr_ee_y[1]', + value: 0.25 + }, + {value: null} + ], + x: { + signal: 'thr_ee_x[0]' + }, + y: { + signal: 'thr_ee_y[0]' + }, + x2: { + signal: 'thr_ee_x[1]' + }, + y2: { + signal: 'thr_ee_y[1]' + } + } } - ] - }); + } + ]); }); - it('namespaces signals when encoding/fields collide', () => { - const model2 = parseUnitModel({ + it('should be robust to same channel/field names', () => { + const nameModel = parseUnitModel({ mark: 'circle', encoding: { x: {field: 'x', type: 'quantitative'}, y: {field: 'y', type: 'quantitative'} } }); + nameModel.parseScale(); - model2.parseScale(); - - const selCmpts2 = (model2.component.selection = parseUnitSelection(model2, [ + const nameSelCmpts = (nameModel.component.selection = parseUnitSelection(nameModel, [ { - name: 'one', - select: { - type: 'interval', - encodings: ['x'], - translate: false, - zoom: false - } + name: 'brush', + select: 'interval' } ])); - const sg = interval.signals(model, selCmpts2['one'], []); - expect(sg[0].name).toBe('one_x_1'); - expect(sg[1].name).toBe('one_x'); - }); - }); + const signals = interval.signals(nameModel, nameSelCmpts['brush'], []); + const names = signals.map(s => s.name); + expect(names).toEqual(expect.arrayContaining(['brush_x_1', 'brush_x', 'brush_y_1', 'brush_y'])); - it('builds modify signals', () => { - const signals = assembleUnitSelectionSignals(model, []); - expect(signals).toEqual( - expect.arrayContaining([ - { - name: 'one_modify', - on: [ - { - events: {signal: 'one_tuple'}, - update: `modify("one_store", one_tuple, true)` - } - ] - }, + const marks: any[] = [{hello: 'world'}]; + expect(interval.marks(nameModel, nameSelCmpts['brush'], marks)).toEqual([ { - name: 'two_modify', - on: [ - { - events: {signal: 'two_tuple'}, - update: `modify("two_store", two_tuple, true)` + name: 'brush_brush_bg', + type: 'rect', + clip: true, + encode: { + enter: {fill: {value: '#333'}, fillOpacity: {value: 0.125}}, + update: { + x: [ + { + test: 'data("brush_store").length && data("brush_store")[0].unit === ""', + signal: 'brush_x_1[0]' + }, + {value: 0} + ], + y: [ + { + test: 'data("brush_store").length && data("brush_store")[0].unit === ""', + signal: 'brush_y_1[0]' + }, + {value: 0} + ], + x2: [ + { + test: 'data("brush_store").length && data("brush_store")[0].unit === ""', + signal: 'brush_x_1[1]' + }, + {value: 0} + ], + y2: [ + { + test: 'data("brush_store").length && data("brush_store")[0].unit === ""', + signal: 'brush_y_1[1]' + }, + {value: 0} + ] } - ] + } }, + {hello: 'world'}, { - name: 'thr_ee_modify', - on: [ - { - events: {signal: 'thr_ee_tuple'}, - update: `modify("thr_ee_store", thr_ee_tuple, {unit: ""})` + name: 'brush_brush', + type: 'rect', + clip: true, + encode: { + enter: {fill: {value: 'transparent'}}, + update: { + x: [ + { + test: 'data("brush_store").length && data("brush_store")[0].unit === ""', + signal: 'brush_x_1[0]' + }, + {value: 0} + ], + y: [ + { + test: 'data("brush_store").length && data("brush_store")[0].unit === ""', + signal: 'brush_y_1[0]' + }, + {value: 0} + ], + x2: [ + { + test: 'data("brush_store").length && data("brush_store")[0].unit === ""', + signal: 'brush_x_1[1]' + }, + {value: 0} + ], + y2: [ + { + test: 'data("brush_store").length && data("brush_store")[0].unit === ""', + signal: 'brush_y_1[1]' + }, + {value: 0} + ], + stroke: [ + { + test: 'brush_x_1[0] !== brush_x_1[1] && brush_y_1[0] !== brush_y_1[1]', + value: 'white' + }, + {value: null} + ] } - ] + } } - ]) - ); + ]); + }); }); - it('builds brush mark', () => { - const marks: any[] = [{hello: 'world'}]; - expect(interval.marks(model, selCmpts['one'], marks)).toEqual([ - { - name: 'one_brush_bg', - type: 'rect', - clip: true, - encode: { - enter: { - fill: {value: '#333'}, - fillOpacity: {value: 0.125} - }, - update: { - x: [ - { - test: 'data("one_store").length && data("one_store")[0].unit === ""', - signal: 'one_x[0]' - }, - { - value: 0 - } - ], - y: [ - { - test: 'data("one_store").length && data("one_store")[0].unit === ""', - value: 0 - }, - { - value: 0 - } - ], - x2: [ - { - test: 'data("one_store").length && data("one_store")[0].unit === ""', - signal: 'one_x[1]' - }, - { - value: 0 - } - ], - y2: [ - { - test: 'data("one_store").length && data("one_store")[0].unit === ""', - field: { - group: 'height' - } - }, - { - value: 0 - } - ] - } + describe('Geo intervals', () => { + const model = parseUnitModelWithScaleAndLayoutSize({ + data: { + url: 'data/airports.csv', + format: { + type: 'csv' } }, - {hello: 'world'}, - { - name: 'one_brush', - type: 'rect', - clip: true, - encode: { - enter: { - fill: {value: 'transparent'} - }, - update: { - stroke: [ - { - test: 'one_x[0] !== one_x[1]', - value: 'white' - }, - { - value: null - } - ], - x: [ - { - test: 'data("one_store").length && data("one_store")[0].unit === ""', - signal: 'one_x[0]' - }, - { - value: 0 - } - ], - y: [ - { - test: 'data("one_store").length && data("one_store")[0].unit === ""', - value: 0 - }, - { - value: 0 - } - ], - x2: [ - { - test: 'data("one_store").length && data("one_store")[0].unit === ""', - signal: 'one_x[1]' - }, - { - value: 0 - } - ], - y2: [ - { - test: 'data("one_store").length && data("one_store")[0].unit === ""', - field: { - group: 'height' - } - }, - { - value: 0 - } - ] - } + mark: 'circle', + projection: { + type: 'albersUsa' + }, + encoding: { + longitude: { + field: 'longitude', + type: 'quantitative' + }, + latitude: { + field: 'latitude', + type: 'quantitative' } } - ]); - - // Scale-bound interval selections should not add a brush mark. - expect(interval.marks(model, selCmpts['two'], marks)).toEqual(marks); + }); + model.parseProjection(); - expect(interval.marks(model, selCmpts['thr_ee'], marks)).toEqual([ + const selCmpts = (model.component.selection = parseUnitSelection(model, [ { - name: 'thr_ee_brush_bg', - type: 'rect', - clip: true, - encode: { - enter: { - fill: {value: 'red'}, - fillOpacity: {value: 0.75} - }, - update: { - x: { - signal: 'thr_ee_x[0]' - }, - y: { - signal: 'thr_ee_y[0]' - }, - x2: { - signal: 'thr_ee_x[1]' - }, - y2: { - signal: 'thr_ee_y[1]' - } - } + name: 'one', + select: {type: 'interval', clear: false, translate: false, zoom: false} + }, + { + name: 'two', + select: {type: 'interval', encodings: ['longitude'], clear: false, translate: false, zoom: false} + }, + { + name: 'three', + select: {type: 'interval', clear: false, translate: false, zoom: false}, + value: { + latitude: [30, 40], + longitude: [-86, -118] } }, - {hello: 'world'}, { - name: 'thr_ee_brush', - type: 'rect', - clip: true, - encode: { - enter: { - fill: {value: 'transparent'} - }, - update: { - stroke: [ - { - test: 'thr_ee_x[0] !== thr_ee_x[1] && thr_ee_y[0] !== thr_ee_y[1]', - value: 'black' - }, - {value: null} - ], - strokeWidth: [ - { - test: 'thr_ee_x[0] !== thr_ee_x[1] && thr_ee_y[0] !== thr_ee_y[1]', - value: 4 - }, - {value: null} - ], - strokeDash: [ - { - test: 'thr_ee_x[0] !== thr_ee_x[1] && thr_ee_y[0] !== thr_ee_y[1]', - value: [10, 5] - }, - {value: null} - ], - strokeDashOffset: [ - { - test: 'thr_ee_x[0] !== thr_ee_x[1] && thr_ee_y[0] !== thr_ee_y[1]', - value: 3 - }, - {value: null} - ], - strokeOpacity: [ - { - test: 'thr_ee_x[0] !== thr_ee_x[1] && thr_ee_y[0] !== thr_ee_y[1]', - value: 0.25 - }, - {value: null} - ], - x: { - signal: 'thr_ee_x[0]' + name: 'four', + select: {type: 'interval', clear: false, translate: false, zoom: false}, + value: {latitude: [30, 40]} + } + ])); + + describe('Tuple Signals', () => { + it('builds projection signals', () => { + const oneSg = interval.signals(model, selCmpts['one'], []); + expect(oneSg).toEqual( + expect.arrayContaining([ + { + name: 'one_latitude_1', + value: [], + on: [ + { + events: parseSelector('mousedown', 'scope')[0], + update: '[y(unit), y(unit)]' + }, + { + events: parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')[0], + update: '[one_latitude_1[0], clamp(y(unit), 0, height)]' + } + ] + }, + { + name: 'one_longitude_1', + value: [], + on: [ + { + events: parseSelector('mousedown', 'scope')[0], + update: '[x(unit), x(unit)]' + }, + { + events: parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')[0], + update: '[one_longitude_1[0], clamp(x(unit), 0, width)]' + } + ] + } + ]) + ); + + const twoSg = interval.signals(model, selCmpts['two'], []); + expect(twoSg).toEqual( + expect.arrayContaining([ + { + name: 'two_longitude_1', + value: [], + on: [ + { + events: parseSelector('mousedown', 'scope')[0], + update: '[x(unit), x(unit)]' + }, + { + events: parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')[0], + update: '[two_longitude_1[0], clamp(x(unit), 0, width)]' + } + ] + } + ]) + ); + + const threeSg = interval.signals(model, selCmpts['three'], []); + expect(threeSg).toEqual( + expect.arrayContaining([ + { + name: 'three_init', + init: '[scale("projection", [-86, 30]), scale("projection", [-118, 40])]' + }, + { + name: 'three_latitude_1', + init: '[three_init[0][1], three_init[1][1]]', + on: [ + { + events: parseSelector('mousedown', 'scope')[0], + update: '[y(unit), y(unit)]' + }, + { + events: parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')[0], + update: '[three_latitude_1[0], clamp(y(unit), 0, height)]' + } + ] }, - y: { - signal: 'thr_ee_y[0]' + { + name: 'three_longitude_1', + init: '[three_init[0][0], three_init[1][0]]', + on: [ + { + events: parseSelector('mousedown', 'scope')[0], + update: '[x(unit), x(unit)]' + }, + { + events: parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')[0], + update: '[three_longitude_1[0], clamp(x(unit), 0, width)]' + } + ] + } + ]) + ); + + const fourSg = interval.signals(model, selCmpts['four'], []); + expect(fourSg).toEqual( + expect.arrayContaining([ + { + name: 'projection_center', + update: 'invert("projection", [width/2, height/2])' }, - x2: { - signal: 'thr_ee_x[1]' + { + name: 'four_init', + init: '[scale("projection", [projection_center[0], 30]), scale("projection", [projection_center[0], 40])]' }, - y2: { - signal: 'thr_ee_y[1]' + { + name: 'four_latitude_1', + init: '[four_init[0][1], four_init[1][1]]', + on: [ + { + events: parseSelector('mousedown', 'scope')[0], + update: '[y(unit), y(unit)]' + }, + { + events: parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')[0], + update: '[four_latitude_1[0], clamp(y(unit), 0, height)]' + } + ] } - } - } - } - ]); - }); + ]) + ); + }); - it('should be robust to same channel/field names', () => { - const nameModel = parseUnitModel({ - mark: 'circle', - encoding: { - x: {field: 'x', type: 'quantitative'}, - y: {field: 'y', type: 'quantitative'} - } - }); - nameModel.parseScale(); + it('builds trigger signals', () => { + const oneSg = interval.signals(model, selCmpts['one'], []); + expect(oneSg).toContainEqual({ + name: 'one_tuple', + on: [ + { + events: [{signal: 'one_longitude_1 || one_latitude_1'}], + update: + 'vlSelectionTuples(intersect([[one_longitude_1[0], one_latitude_1[0]],[one_longitude_1[1], one_latitude_1[1]]], {markname: "marks"}, unit.mark), {unit: ""})' + } + ] + }); - const nameSelCmpts = (nameModel.component.selection = parseUnitSelection(nameModel, [ - { - name: 'brush', - select: 'interval' - } - ])); + const twoSg = interval.signals(model, selCmpts['two'], []); + expect(twoSg).toContainEqual({ + name: 'two_tuple', + on: [ + { + events: [{signal: 'two_longitude_1'}], + update: + 'vlSelectionTuples(intersect([[two_longitude_1[0], 0],[two_longitude_1[1], height]], {markname: "marks"}, unit.mark), {unit: ""})' + } + ] + }); - const signals = interval.signals(nameModel, nameSelCmpts['brush'], []); - const names = signals.map(s => s.name); - expect(names).toEqual(expect.arrayContaining(['brush_x_1', 'brush_x', 'brush_y_1', 'brush_y'])); + const threeSg = interval.signals(model, selCmpts['three'], []); + let update = + 'vlSelectionTuples(intersect([[three_longitude_1[0], three_latitude_1[0]],[three_longitude_1[1], three_latitude_1[1]]], {markname: "marks"}, unit.mark), {unit: ""})'; + expect(threeSg).toContainEqual({ + name: 'three_tuple', + on: [{events: [{signal: 'three_latitude_1 || three_longitude_1'}, {signal: GEO_INIT_TICK}], update}] + }); - const marks: any[] = [{hello: 'world'}]; - expect(interval.marks(nameModel, nameSelCmpts['brush'], marks)).toEqual([ - { - name: 'brush_brush_bg', - type: 'rect', - clip: true, - encode: { - enter: {fill: {value: '#333'}, fillOpacity: {value: 0.125}}, - update: { - x: [ - { - test: 'data("brush_store").length && data("brush_store")[0].unit === ""', - signal: 'brush_x_1[0]' - }, - {value: 0} - ], - y: [ - { - test: 'data("brush_store").length && data("brush_store")[0].unit === ""', - signal: 'brush_y_1[0]' - }, - {value: 0} - ], - x2: [ - { - test: 'data("brush_store").length && data("brush_store")[0].unit === ""', - signal: 'brush_x_1[1]' - }, - {value: 0} - ], - y2: [ - { - test: 'data("brush_store").length && data("brush_store")[0].unit === ""', - signal: 'brush_y_1[1]' - }, - {value: 0} - ] - } - } - }, - {hello: 'world'}, - { - name: 'brush_brush', - type: 'rect', - clip: true, - encode: { - enter: {fill: {value: 'transparent'}}, - update: { - x: [ - { - test: 'data("brush_store").length && data("brush_store")[0].unit === ""', - signal: 'brush_x_1[0]' - }, - {value: 0} - ], - y: [ - { - test: 'data("brush_store").length && data("brush_store")[0].unit === ""', - signal: 'brush_y_1[0]' - }, - {value: 0} - ], - x2: [ - { - test: 'data("brush_store").length && data("brush_store")[0].unit === ""', - signal: 'brush_x_1[1]' - }, - {value: 0} - ], - y2: [ - { - test: 'data("brush_store").length && data("brush_store")[0].unit === ""', - signal: 'brush_y_1[1]' - }, - {value: 0} - ], - stroke: [ - { - test: 'brush_x_1[0] !== brush_x_1[1] && brush_y_1[0] !== brush_y_1[1]', - value: 'white' - }, - {value: null} - ] - } - } - } - ]); + const fourSg = interval.signals(model, selCmpts['four'], []); + update = + 'vlSelectionTuples(intersect([[0, four_latitude_1[0]],[width, four_latitude_1[1]]], {markname: "marks"}, unit.mark), {unit: ""})'; + expect(fourSg).toContainEqual({ + name: 'four_tuple', + on: [{events: [{signal: 'four_latitude_1'}, {signal: GEO_INIT_TICK}], update}] + }); + }); + }); }); }); diff --git a/test/compile/selection/parse.test.ts b/test/compile/selection/parse.test.ts index 2600ebb07ca..f2a57b9ac43 100644 --- a/test/compile/selection/parse.test.ts +++ b/test/compile/selection/parse.test.ts @@ -29,7 +29,7 @@ describe('Selection', () => { expect(component.one.name).toBe('one'); expect(component.one.type).toBe('point'); expect(component['one'].project.items).toEqual( - expect.arrayContaining([{field: '_vgsid_', type: 'E', signals: {data: 'one__vgsid_'}}]) + expect.arrayContaining([{field: '_vgsid_', index: 0, type: 'E', signals: {data: 'one__vgsid_'}}]) ); expect(component['one'].events).toEqual(parseSelector('click', 'scope')); @@ -39,16 +39,28 @@ describe('Selection', () => { expect(component.two.zoom).toBe('wheel!'); expect(component['two'].project.items).toEqual( expect.arrayContaining([ - {field: 'Horsepower', channel: 'x', type: 'R', signals: {data: 'two_Horsepower', visual: 'two_x'}}, + { + field: 'Horsepower', + channel: 'x', + index: 0, + type: 'R', + signals: {data: 'two_Horsepower', visual: 'two_x'} + }, { field: 'Miles_per_Gallon', channel: 'y', + index: 1, type: 'R', signals: {data: 'two_Miles_per_Gallon', visual: 'two_y'} } ]) ); - expect(component['two'].events).toEqual(parseSelector('[mousedown, window:mouseup] > window:mousemove!', 'scope')); + expect(component['two'].events).toEqual( + parseSelector( + '[mousedown[!event.item || event.item.mark.name !== "two_brush"], window:mouseup] > window:mousemove!', + 'scope' + ) + ); }); it('supports inline default overrides', () => { @@ -87,7 +99,7 @@ describe('Selection', () => { expect(component.one.name).toBe('one'); expect(component.one.type).toBe('point'); expect(component['one'].project.items).toEqual( - expect.arrayContaining([{field: 'Cylinders', type: 'E', signals: {data: 'one_Cylinders'}}]) + expect.arrayContaining([{field: 'Cylinders', index: 0, type: 'E', signals: {data: 'one_Cylinders'}}]) ); expect(component['one'].events).toEqual(parseSelector('dblclick', 'scope')); @@ -96,7 +108,7 @@ describe('Selection', () => { expect(component.two.toggle).toBe('event.ctrlKey'); expect(component['two'].project.items).toEqual( expect.arrayContaining([ - {field: 'Origin', channel: 'color', type: 'E', signals: {data: 'two_Origin', visual: 'two_color'}} + {field: 'Origin', channel: 'color', index: 0, type: 'E', signals: {data: 'two_Origin', visual: 'two_color'}} ]) ); expect(component['two'].events).toEqual(parseSelector('mouseover', 'scope')); @@ -110,6 +122,7 @@ describe('Selection', () => { { field: 'Miles_per_Gallon', channel: 'y', + index: 0, type: 'R', signals: {data: 'three_Miles_per_Gallon', visual: 'three_y'} } @@ -142,7 +155,7 @@ describe('Selection', () => { expect(component.one.toggle).toBe('event.ctrlKey'); expect(component['one'].project.items).toEqual( expect.arrayContaining([ - {field: 'Origin', channel: 'color', type: 'E', signals: {data: 'one_Origin', visual: 'one_color'}} + {field: 'Origin', channel: 'color', index: 0, type: 'E', signals: {data: 'one_Origin', visual: 'one_color'}} ]) ); expect(component['one'].events).toEqual(parseSelector('mouseover', 'scope')); @@ -156,6 +169,7 @@ describe('Selection', () => { { field: 'Miles_per_Gallon', channel: 'y', + index: 0, type: 'R', signals: {data: 'two_Miles_per_Gallon', visual: 'two_y'} } @@ -182,7 +196,7 @@ describe('Selection', () => { expect(c['one'].project.items).toEqual( expect.arrayContaining([ - {field: 'Origin', channel: 'x', type: 'E', signals: {data: 'one_Origin', visual: 'one_x'}} + {field: 'Origin', channel: 'x', index: 0, type: 'E', signals: {data: 'one_Origin', visual: 'one_x'}} ]) ); @@ -200,7 +214,7 @@ describe('Selection', () => { expect(c['one'].project.items).toEqual( expect.arrayContaining([ - {field: 'Origin', channel: 'x', type: 'E', signals: {data: 'one_Origin', visual: 'one_x'}} + {field: 'Origin', channel: 'x', index: 0, type: 'E', signals: {data: 'one_Origin', visual: 'one_x'}} ]) ); }); @@ -218,7 +232,13 @@ describe('Selection', () => { expect(c['one'].project.items).toEqual( expect.arrayContaining([ - {field: 'Acceleration', channel: 'x', type: 'R-RE', signals: {data: 'one_Acceleration', visual: 'one_x'}} + { + field: 'Acceleration', + channel: 'x', + index: 0, + type: 'R-RE', + signals: {data: 'one_Acceleration', visual: 'one_x'} + } ]) ); }); @@ -243,18 +263,24 @@ describe('Selection', () => { ]); expect(component['one'].project.items).toEqual( - expect.arrayContaining([{field: 'Origin', type: 'E', signals: {data: 'one_Origin'}}]) + expect.arrayContaining([{field: 'Origin', index: 0, type: 'E', signals: {data: 'one_Origin'}}]) ); expect(component['two'].project.items).toEqual( expect.arrayContaining([ - {channel: 'color', field: 'Origin', type: 'E', signals: {data: 'two_Origin', visual: 'two_color'}} + {channel: 'color', field: 'Origin', index: 0, type: 'E', signals: {data: 'two_Origin', visual: 'two_color'}} ]) ); expect(component['three'].project.items).toEqual( expect.arrayContaining([ - {field: 'Horsepower', channel: 'x', type: 'R', signals: {data: 'three_Horsepower', visual: 'three_x'}} + { + field: 'Horsepower', + channel: 'x', + index: 0, + type: 'R', + signals: {data: 'three_Horsepower', visual: 'three_x'} + } ]) ); }); @@ -268,8 +294,8 @@ describe('Selection', () => { ]); expect(component['one'].project.items).toEqual([ - {field: 'nested.a', type: 'E', signals: {data: 'one_nested_a'}}, - {field: 'nested.b.aa', type: 'E', signals: {data: 'one_nested_b_aa'}} + {field: 'nested.a', index: 0, type: 'E', signals: {data: 'one_nested_a'}}, + {field: 'nested.b.aa', index: 1, type: 'E', signals: {data: 'one_nested_b_aa'}} ]); expect(project.signals(null, component['one'], [])).toEqual([ @@ -292,8 +318,14 @@ describe('Selection', () => { ]); expect(component['one'].project.items).toEqual([ - {field: 'Horsepower', channel: 'x', type: 'E', signals: {data: 'one_Horsepower', visual: 'one_x'}}, - {field: 'Miles_per_Gallon', channel: 'y', type: 'E', signals: {data: 'one_Miles_per_Gallon', visual: 'one_y'}} + {field: 'Horsepower', channel: 'x', index: 0, type: 'E', signals: {data: 'one_Horsepower', visual: 'one_x'}}, + { + field: 'Miles_per_Gallon', + channel: 'y', + index: 1, + type: 'E', + signals: {data: 'one_Miles_per_Gallon', visual: 'one_y'} + } ]); }); });