Status: Not Started Priority: Medium Complexity: Medium-High
Enable chart elements to respond to clicks, allowing users to: - Set variables by clicking on chart elements (drill-down) - Filter other charts based on clicked values - Navigate to URLs - Navigate to detail dashboards
dataface/compile/types.py:
```python
class ChartInteractionClick(BaseModel):
action: Literal["filter", "open_link", "set_variable", "drill"]
target: Union[str, List[str]]
value_map: Optional[Dict[str, Any]] = Noneclass ChartInteractions(BaseModel): click: Optional[ChartInteractionClick] = None hover: Optional[Dict[str, Any]] = None ```
YAML schema supports interactions - users can define them in YAML but they don't work
Documentation exists (now marked as "coming soon")
generate_vega_lite_spec() ignores interactionsvegaEmbed() has no event listenersRecommendation: Hybrid approach
This matches how variables already work (dropdowns trigger server re-render) and avoids complex client-side state management.
set_variable Action (HTML Renderer)The most common use case. When a user clicks a chart element, update a variable.
In dataface/render/vega_lite.py, add click selection params when interactions.click is present:
def generate_vega_lite_spec(...):
# ... existing code ...
# Add click selection if interactions defined
interactions = getattr(chart, "interactions", None)
if interactions and interactions.click:
click_config = interactions.click
if click_config.action == "set_variable":
# Add selection parameter for click detection
spec["params"] = spec.get("params", [])
spec["params"].append({
"name": "click_select",
"select": {
"type": "point",
"on": "click",
"fields": [click_config.value_map.get("field")]
}
})
In dataface/render/html.py, add JavaScript event handling:
def _render_chart(...):
# ... existing code ...
interactions = getattr(chart, "interactions", None)
click_handler = ""
if interactions and interactions.click:
click = interactions.click
if click.action == "set_variable":
target_var = click.target
field = click.value_map.get("field") if click.value_map else None
if target_var and field:
click_handler = f"""
view.addEventListener('click', function(event, item) {{
if (item && item.datum && item.datum['{field}']) {{
const value = item.datum['{field}'];
// Update the form input
const input = document.querySelector('[name="{target_var}"]');
if (input) {{
input.value = value;
input.dispatchEvent(new Event('change', {{ bubbles: true }}));
}}
}}
}});
"""
return f"""
<div class="dataface-chart" ...>
<div id="{chart_id}-content" ...></div>
</div>
<script>
vegaEmbed('#{chart_id}-content', {spec_json}, {{actions: {{editor: false}}}})
.then(function(result) {{
const view = result.view;
{click_handler}
}})
.catch(console.error);
</script>
"""
The HTML renderer already creates form inputs for variables. When a click handler updates an input's value and dispatches a change event, the form should auto-submit (or use JavaScript to trigger re-render).
For the playground, this would require WebSocket integration to send the variable update.
The playground needs to handle variable updates from chart clicks.
In dataface/playground/static/playground.js:
// Listen for variable changes from chart clicks
document.addEventListener('change', function(event) {
if (event.target.matches('.dataface-variable-input')) {
// Send updated variables via WebSocket
const variables = collectVariables();
sendVariableUpdate(variables);
}
});
Add a WebSocket handler for variable updates that triggers re-render.
filter ActionFilter other charts based on clicked value. This is similar to set_variable but targets specific charts rather than variables.
interactions:
click:
action: filter
target: ["chart1", "chart2"]
value_map:
field: "category"
Implementation: Use Vega-Lite signals to filter data in specified charts (client-side only).
link ActionNavigate to a URL:
interactions:
click:
action: link
target: "https://example.com/detail/{{ datum.id }}"
Implementation: Simple JavaScript window.location.href or window.open().
drill ActionNavigate to a detail dashboard:
interactions:
click:
action: drill
target: "detail_dashboard.yml"
Implementation: Navigate with URL parameters for selected values.
Add visual cues that charts are clickable:
cursor: pointer on hover| File | Changes |
|---|---|
dataface/render/vega_lite.py |
Add click selection params to spec |
dataface/render/html.py |
Add JavaScript event handlers |
dataface/playground/static/playground.js |
Handle variable updates from clicks |
dataface/playground/routes.py |
WebSocket handler for variable updates |
tests/unit/test_vega_lite.py |
Test click spec generation |
tests/integration/test_interactions.py |
End-to-end click tests |
link actionfilter actiondrill actionWhen click interactions are implemented, restore documentation in the following files:
examples/variables/interactive.ymlRestore click interaction to the product chart:
# In the "About This Dashboard" content section, restore:
content: |
**Click on any bar** in the charts below to filter and see detailed sales trends.
This demonstrates Dataface's interactive features:
- ๐ฑ๏ธ **Click interactions** โ Select data points to filter other charts
- ๐ **Dynamic titles** โ Chart titles update based on your selection
- ๐ **Real-time filtering** โ See detailed data for your selection
- ๐ฆ **Nested variables** โ Variables scoped to their section
# Rename product_revenue back to product_selector and add interactions:
charts:
product_selector:
title: "Click a Product to View Details"
query: sales
type: bar
x: product
y: revenue
color: category
filters:
region: "{{ region }}"
interactions:
click:
action: set_variable
target: "selected_product"
value_map:
field: "product"
docs/docs/charts/interactions.mdRemove "Coming Soon" notice and restore working examples:
# Set Variable on Click example
charts:
month_selector:
query: _doc_examples.yaml#sales
type: bar
title: Click a Month to Select
x: date
y: revenue
interactions:
click:
action: set_variable
target: "selected_month"
value_map:
field: "date"
# Filter Other Charts example
charts:
region_filter:
title: "Click to Filter"
query: queries.sales
type: bar
x: region
y: total_revenue
interactions:
click:
action: filter
target: ["sales_chart", "orders_chart"]
# Link to URL example
charts:
drill_down:
title: "Click to Drill Down"
query: queries.sales
type: bar
x: month
y: total_revenue
interactions:
click:
action: link
target: "https://example.com/detail"
docs/docs/examples/drill-down.mdRemove "Coming Soon" warning banner and "Planned" from title. The full original content showed:
title: "Interactive Sales Board"
variables:
selected_month:
input: select
default: ""
queries:
monthly_sales:
metrics: [total_revenue]
dimensions: [month, region]
monthly_detail:
metrics: [total_revenue, order_count]
dimensions: [day, product]
filters:
month: selected_month
rows:
- title: "Monthly Overview"
cols:
- month_selector:
title: "Click a Month to View Details"
query: queries.monthly_sales
type: bar
x: month
y: total_revenue
color: region
interactions:
click:
action: set_variable
target: "selected_month"
value_map:
field: "month"
format: "YYYY-MM"
- month_detail:
title: "Daily Sales for Selected Month"
query: queries.monthly_detail
type: line
x: day
y: total_revenue
color: product
docs/docs/examples/interactive.mdRestore the "Add Chart Interactions" extension section:
### Add Chart Interactions
Make charts interactive:
\`\`\`yaml
charts:
region_chart:
# ...
interactions:
click:
action: set_variable
target: "region"
value_map:
field: "region"
\`\`\`
And restore link to drill-down:
- [Drill-Down Example](drill-down.md) - Add click interactions
docs/docs/reference/quick-reference.mdRestore interactions to chart template:
charts:
revenue_trend:
title: "Revenue Trend"
query: queries.sales
type: line
x: month
y: revenue
color: region
style:
show_legend: true
interactions:
click:
action: filter
target: region
And restore "Drill Down Interaction" pattern:
### Drill Down Interaction
charts:
main_bar:
type: bar
interactions:
click:
action: set_variable
target: selected_category
value_map:
field: category
docs/docs/reference/field-reference.mdRemove "Coming Soon" notice from Interaction section:
## Interaction
\`\`\`yaml
# Interaction
interactions:
click:
action: string # Required: filter|open_link|set_variable
target: string # Target variable or link pattern
hover:
tooltip: boolean # Show tooltip (default: true)
columns: [string] # Custom tooltip columns
\`\`\`
docs/docs/charts/index.mdRemove "Coming soon" comments and restore:
# Interactions
interactions:
click:
action: drill | filter | link | set_variable
target: string | [string]
value_map:
field: string
format: string
hover:
tooltip: boolean
And in Best Practices:
### Interactions
- Use click actions for drill-downs
- Set variables for cross-chart filtering
- Provide tooltips for context
See [Interactions](interactions.md) for details.
And in Related:
- [Interactions](interactions.md) - Click, filter, and hover behaviors
Performance: Re-rendering entire board on click may be slow - Mitigation: Consider partial updates (only affected charts)
State Management: Client-side vs server-side state synchronization - Mitigation: Use server as source of truth, client for visual feedback only
Complexity: Vega-Lite selection API can be complex - Mitigation: Start with simple point selection, expand later
Testing: Difficult to test JavaScript interactions in Python tests - Mitigation: Use browser automation (Playwright) for integration tests