ai_notes/features/CLICK_INTERACTIONS.md

Click Interactions Implementation Plan

Status: Not Started Priority: Medium Complexity: Medium-High

Overview

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

Current State

What Exists

  1. Types are defined in 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]] = None

class ChartInteractions(BaseModel): click: Optional[ChartInteractionClick] = None hover: Optional[Dict[str, Any]] = None ```

  1. YAML schema supports interactions - users can define them in YAML but they don't work

  2. Documentation exists (now marked as "coming soon")

What's Missing

  1. Vega-Lite specs don't include click signals - generate_vega_lite_spec() ignores interactions
  2. No JavaScript to handle clicks - vegaEmbed() has no event listeners
  3. No variable update mechanism - No way to update variables from chart clicks
  4. No chart re-rendering - No mechanism to update dependent charts when variables change

Implementation Approach

Architecture Decision: Server-Side vs Client-Side

Recommendation: Hybrid approach

This matches how variables already work (dropdowns trigger server re-render) and avoids complex client-side state management.

Phase 1: Basic set_variable Action (HTML Renderer)

The most common use case. When a user clicks a chart element, update a variable.

1.1 Modify Vega-Lite Spec Generation

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")]
                }
            })

1.2 Modify HTML Chart Rendering

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>
    """

1.3 Variable Form Integration

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.

Phase 2: Playground Support

The playground needs to handle variable updates from chart clicks.

2.1 Add Click Event Handling to Playground JS

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);
    }
});

2.2 Modify Playground Routes

Add a WebSocket handler for variable updates that triggers re-render.

Phase 3: Additional Actions

3.1 filter Action

Filter 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).

Navigate to a URL:

interactions:
  click:
    action: link
    target: "https://example.com/detail/{{ datum.id }}"

Implementation: Simple JavaScript window.location.href or window.open().

3.3 drill Action

Navigate to a detail dashboard:

interactions:
  click:
    action: drill
    target: "detail_dashboard.yml"

Implementation: Navigate with URL parameters for selected values.

Phase 4: Visual Feedback

Add visual cues that charts are clickable:

  1. Cursor change: cursor: pointer on hover
  2. Highlight on hover: Subtle opacity/color change
  3. Selection indication: Show which element is selected

Testing Strategy

Unit Tests

  1. Vega-Lite spec generation - Verify click params are added correctly
  2. HTML rendering - Verify JavaScript handlers are generated

Integration Tests

  1. Click interaction flow - Simulate click, verify variable update
  2. Dependent chart update - Verify filtered charts re-render

Manual Testing (Playground)

  1. Create example with click interactions
  2. Verify clicks update variables
  3. Verify dependent charts update

Files to Modify

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

Milestones

Milestone 1: Basic set_variable (2-3 days)

Milestone 2: Playground Integration (1-2 days)

Milestone 3: Additional Actions (2-3 days)

Milestone 4: Polish (1 day)

Documentation to Restore After Implementation

When click interactions are implemented, restore documentation in the following files:

Example Files

examples/variables/interactive.yml

Restore 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"

Documentation Files

docs/docs/charts/interactions.md

Remove "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.md

Remove "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.md

Restore 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.md

Restore 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.md

Remove "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.md

Remove "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

Risks & Considerations

  1. Performance: Re-rendering entire board on click may be slow - Mitigation: Consider partial updates (only affected charts)

  2. State Management: Client-side vs server-side state synchronization - Mitigation: Use server as source of truth, client for visual feedback only

  3. Complexity: Vega-Lite selection API can be complex - Mitigation: Start with simple point selection, expand later

  4. Testing: Difficult to test JavaScript interactions in Python tests - Mitigation: Use browser automation (Playwright) for integration tests