mirror of
https://github.com/olehomelchenko/astrolabe-nvc.git
synced 2025-12-21 21:22:23 +00:00
389 lines
16 KiB
Markdown
389 lines
16 KiB
Markdown
# Chart Builder Feature - Implementation Document
|
||
|
||
## Overview
|
||
Add a "Build Chart" button to the dataset details panel that launches a visual chart builder. This helps users bootstrap visualizations from datasets without writing Vega-Lite JSON manually.
|
||
|
||
## Feature Scope
|
||
|
||
### Included
|
||
- **Mark types**: bar, line, point, area, circle
|
||
- **Encoding channels**: X, Y, Color, Size (all optional, but at least one required)
|
||
- **Field type selection**: Q (quantitative), O (ordinal), N (nominal), T (temporal)
|
||
- **Dimensions**: Width and Height controls (number inputs, empty = auto)
|
||
- **Live preview**: Real-time chart preview in right panel
|
||
- **Auto-defaults**: Pre-populate based on detected column types
|
||
- **URL state**: Support `#datasets/dataset-123/build` routing
|
||
|
||
### Explicitly Out of Scope
|
||
- No transform support (filter, calculate, etc.)
|
||
- No layer/concat/facet composition
|
||
- No conditional encodings
|
||
- No legend/axis customization
|
||
- No mark properties (opacity, stroke, etc.)
|
||
- No aggregation functions (count, sum, mean)
|
||
|
||
Users can manually edit generated specs in the editor for advanced features.
|
||
|
||
## User Flow
|
||
|
||
1. **Entry Point**: User selects dataset → clicks "Build Chart" button (next to "New Snippet")
|
||
2. **Builder Modal Opens**: Chart builder interface with config + preview
|
||
3. **Configuration**:
|
||
- Select mark type from dropdown
|
||
- Set width/height (optional)
|
||
- Map columns to encoding channels (X, Y, Color, Size)
|
||
- Select data type for each encoding (Q/O/N/T)
|
||
4. **Live Preview**: Right panel shows real-time chart as user configures
|
||
5. **Validation**: "Create Snippet" button disabled until at least one encoding is set
|
||
6. **Save**: Creates new snippet with generated spec, closes builder, opens snippet
|
||
|
||
## Technical Architecture
|
||
|
||
### Configuration Schema (Vega-Lite Compatible)
|
||
|
||
```javascript
|
||
// Chart builder state - directly maps to Vega-Lite spec
|
||
{
|
||
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
|
||
"data": {"name": "dataset-name"}, // Set when opening builder
|
||
"mark": {"type": "bar", "tooltip": true},
|
||
"width": undefined, // undefined = omit from spec (auto)
|
||
"height": undefined,
|
||
"encoding": {
|
||
"x": {"field": "column1", "type": "quantitative"},
|
||
"y": {"field": "column2", "type": "nominal"}
|
||
// color, size added conditionally if set
|
||
}
|
||
}
|
||
```
|
||
|
||
- `currentDatasetName` stored separately in window state (not in spec)
|
||
- Empty encodings omitted from final spec
|
||
- Tooltip always enabled on marks
|
||
|
||
### Generated Vega-Lite Spec Example
|
||
|
||
```json
|
||
{
|
||
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
|
||
"data": {"name": "my-dataset"},
|
||
"mark": {"type": "bar", "tooltip": true},
|
||
"width": 400,
|
||
"height": 300,
|
||
"encoding": {
|
||
"x": {"field": "category", "type": "nominal"},
|
||
"y": {"field": "value", "type": "quantitative"}
|
||
}
|
||
}
|
||
```
|
||
|
||
### Column Type Auto-Mapping
|
||
|
||
Based on existing `dataset.columnTypes`:
|
||
- `number` → Q (quantitative)
|
||
- `date` → T (temporal)
|
||
- `text` → N (nominal)
|
||
- `boolean` → N (nominal)
|
||
|
||
### Default Behavior
|
||
|
||
When opening builder:
|
||
1. Mark type: `bar`
|
||
2. Width/Height: empty (auto)
|
||
3. X axis: First column with auto-detected type
|
||
4. Y axis: Second column (if exists) with auto-detected type
|
||
5. Color/Size: Empty (none)
|
||
6. Preview renders immediately with defaults
|
||
|
||
### Validation Rules
|
||
|
||
- At least one encoding (X or Y) must have a field selected
|
||
- "Create Snippet" button disabled until valid
|
||
- Error message displayed if configuration is invalid
|
||
|
||
## UI Layout
|
||
|
||
### Modal Structure
|
||
```
|
||
┌────────────────────────────────────────────────────────────┐
|
||
│ Build Chart [×] │
|
||
├─────────────────────┬──────────────────────────────────────┤
|
||
│ [← Back to Dataset] │ │
|
||
│ │ │
|
||
│ Mark Type * │ PREVIEW PANEL │
|
||
│ [Dropdown: bar ▾] │ │
|
||
│ │ Live chart preview │
|
||
│ Dimensions │ (centered, auto overflow) │
|
||
│ Width: [ auto ] │ │
|
||
│ Height:[ auto ] │ │
|
||
│ │ │
|
||
│ Encodings │ │
|
||
│ │ │
|
||
│ X Axis │ │
|
||
│ Field: [Drop ▾] │ │
|
||
│ Type: [Q][O][N][T]│ │
|
||
│ │ │
|
||
│ Y Axis │ │
|
||
│ Field: [Drop ▾] │ │
|
||
│ Type: [Q][O][N][T]│ │
|
||
│ │ │
|
||
│ Color (optional) │ │
|
||
│ Field: [Drop ▾] │ │
|
||
│ Type: [Q][O][N][T]│ │
|
||
│ │ │
|
||
│ Size (optional) │ │
|
||
│ Field: [Drop ▾] │ │
|
||
│ Type: [Q][O][N][T]│ │
|
||
│ │ │
|
||
│ [Cancel] │ │
|
||
│ [Create Snippet] │ │
|
||
└─────────────────────┴──────────────────────────────────────┘
|
||
33.33% width 66.67% width
|
||
```
|
||
|
||
### Type Toggle Buttons
|
||
Styled like existing "Draft/Published" buttons in editor header:
|
||
- Four buttons per encoding: `[Q] [O] [N] [T]`
|
||
- Toggle group with border
|
||
- Active state: blue background with white text
|
||
- Single selection (radio button behavior)
|
||
|
||
## Implementation Status
|
||
|
||
### ✅ FEATURE COMPLETE - Chart Builder Fully Functional
|
||
|
||
All implementation steps have been completed. The chart builder is now fully functional and ready for testing.
|
||
|
||
### ✅ Completed: Step 1 - HTML Frame, CSS & Basic Wiring
|
||
|
||
#### Files Modified:
|
||
1. **`index.html`**
|
||
- Added `#chart-builder-modal` after `#extract-modal` (lines 361-508)
|
||
- Added "Build Chart" button to dataset actions (line 204)
|
||
- Added script tag for chart-builder.js (line 876)
|
||
- Modal structure includes:
|
||
- Header with title + close button
|
||
- Left panel: configuration controls (33.33% width)
|
||
- Right panel: preview area (66.67% width)
|
||
- All form controls with proper IDs
|
||
|
||
2. **`src/styles.css`**
|
||
- Added chart builder styles (lines 491-547)
|
||
- Two-column layout: `.chart-builder-container`
|
||
- Config panel: `.chart-builder-config` (scrollable with light gray background)
|
||
- Preview panel: `.chart-builder-preview` (centered content)
|
||
- Mark type toggle group: `.mark-toggle-group` (Bar/Line/Point/Area/Circle buttons)
|
||
- Type toggle groups: `.type-toggle-group` (Q/O/N/T buttons)
|
||
- Dark theme support for all elements
|
||
- Fixed button height/padding to prevent text clipping
|
||
|
||
3. **`src/js/chart-builder.js`** (NEW)
|
||
- `openChartBuilder(datasetId)` - Opens modal and stores dataset ID
|
||
- `closeChartBuilder()` - Closes modal and cleans up state
|
||
- `initializeChartBuilder()` - Sets up event listeners for buttons
|
||
- Global state: `window.chartBuilderState`
|
||
|
||
4. **`src/js/app.js`**
|
||
- Added "Build Chart" button click handler (lines 286-294)
|
||
- Added `initializeChartBuilder()` call (line 115)
|
||
- Button triggers `openChartBuilder(window.currentDatasetId)`
|
||
|
||
#### UI Components Added:
|
||
- **Mark type toggle buttons** (Bar/Line/Point/Area/Circle) - on same line as label
|
||
- **Width/Height number inputs** - at bottom of config panel
|
||
- **4 encoding sections** (X, Y, Color, Size):
|
||
- Label + dropdown on same row
|
||
- Type buttons (Q/O/N/T) on row below
|
||
- **Error display area**
|
||
- **Action buttons** (Create Snippet, Cancel)
|
||
- **Back button** (returns to dataset details)
|
||
|
||
#### Current State:
|
||
✅ Modal opens when clicking "Build Chart" from dataset details
|
||
✅ Modal closes with X button, Cancel button, or Back button
|
||
✅ UI layout matches design requirements
|
||
✅ All styling issues resolved (text no longer clipped)
|
||
|
||
### ✅ Completed: Step 2 - Full JavaScript Implementation
|
||
|
||
#### Files Modified:
|
||
1. **`src/js/chart-builder.js`** ✅ COMPLETE
|
||
- ✅ Populate field dropdowns from dataset columns
|
||
- ✅ Implement mark type toggle functionality (Bar/Line/Point/Area/Circle)
|
||
- ✅ Implement encoding type toggle functionality (Q/O/N/T)
|
||
- ✅ Generate Vega-Lite spec from UI state
|
||
- ✅ Validate configuration (at least one encoding required)
|
||
- ✅ Create snippet from generated spec
|
||
- ✅ Auto-select smart defaults based on column types
|
||
- ✅ Debounced preview rendering using existing settings
|
||
- ✅ URL state management integration
|
||
- ✅ Reuse `resolveDatasetReferences()` from editor.js
|
||
- ~468 lines of fully functional code
|
||
|
||
2. **`src/js/config.js`** ✅ COMPLETE
|
||
- ✅ Updated URLState.parse() to support `#datasets/dataset-123/build`
|
||
- ✅ Updated URLState.update() to generate chart builder URLs
|
||
- ✅ Added chart-builder-modal to ModalManager.closeAny() for ESC key support
|
||
|
||
3. **`src/js/app.js`** ✅ COMPLETE
|
||
- ✅ Updated handleURLStateChange() to handle chart builder action
|
||
- ✅ Opens chart builder when URL contains `/build` suffix
|
||
- ✅ Chart builder integrated with browser back/forward navigation
|
||
|
||
### ✅ All Core Tasks Complete
|
||
|
||
#### ✅ Step 2: Core JavaScript Functionality
|
||
All functions implemented in `chart-builder.js`:
|
||
- ✅ `openChartBuilder(datasetId)` - Initialize builder with dataset
|
||
- ✅ `closeChartBuilder()` - Close modal and cleanup
|
||
- ✅ `initializeChartBuilder()` - Set up event listeners
|
||
- ✅ `updateChartBuilderPreview()` - Debounced preview render
|
||
- ✅ `generateVegaLiteSpec()` - Build spec from UI state
|
||
- ✅ `validateChartConfig()` - Check if config is valid
|
||
- ✅ `createSnippetFromBuilder()` - Generate and save snippet
|
||
- ✅ `populateFieldDropdowns(dataset)` - Fill dropdowns with columns
|
||
- ✅ `autoSelectDefaults(dataset)` - Smart defaults based on types
|
||
- ✅ `mapColumnTypeToVegaType()` - Convert dataset types to Vega-Lite types
|
||
- ✅ `setEncoding()` - Update UI and state for encodings
|
||
- ✅ `renderChartBuilderPreview()` - Render preview with error handling
|
||
|
||
#### ✅ Step 3: Preview Rendering (No Refactor Needed)
|
||
- ✅ Reused existing `resolveDatasetReferences()` from editor.js
|
||
- ✅ Used `window.vegaEmbed()` directly in chart builder
|
||
- ✅ No need for additional refactoring - kept code simple
|
||
|
||
#### ✅ Step 4: Integration
|
||
- ✅ "Build Chart" button already wired in `index.html` (line 204)
|
||
- ✅ Button handler already set up in `app.js` (lines 286-294)
|
||
- ✅ URL state handling implemented in `config.js` and `app.js`
|
||
- ✅ Back button, Cancel, Close, and ESC key all work correctly
|
||
- ✅ URL updates properly when opening/closing builder
|
||
- ✅ Browser back/forward navigation fully supported
|
||
|
||
#### 📋 Step 5: Testing & Polish (Ready for Manual Testing)
|
||
The following should be tested manually:
|
||
- [ ] Test with datasets of different types (JSON, CSV, TSV)
|
||
- [ ] Test with datasets with many columns
|
||
- [ ] Test with datasets with few columns (edge cases)
|
||
- [ ] Test URL state navigation (back/forward buttons)
|
||
- [ ] Test keyboard shortcuts (ESC to close)
|
||
- [ ] Test dark theme compatibility
|
||
- [ ] Test all mark types (Bar, Line, Point, Area, Circle)
|
||
- [ ] Test all encoding types (Q, O, N, T)
|
||
- [ ] Test dimension inputs (width/height)
|
||
- [ ] Test error handling (invalid specs, missing data)
|
||
|
||
## Code Organization
|
||
|
||
### Event Flow
|
||
|
||
```
|
||
User clicks "Build Chart" → openChartBuilder(datasetId)
|
||
→ Fetch dataset, populate dropdowns, auto-select defaults
|
||
→ Show modal, update URL to #datasets/dataset-123/build
|
||
|
||
User changes config → Update state → Debounced preview update
|
||
|
||
User clicks "Create Snippet" → Validate → Generate spec
|
||
→ Create snippet → Close modals → Open in editor
|
||
```
|
||
|
||
### Key Functions
|
||
|
||
- `openChartBuilder(datasetId)` - Initialize builder with dataset
|
||
- `populateFieldDropdowns(dataset)` - Fill dropdowns with columns
|
||
- `autoSelectDefaults(dataset)` - Smart defaults based on types
|
||
- `setEncoding(channel, field, type)` - Update UI and state
|
||
- `generateVegaLiteSpec()` - Build spec from UI state
|
||
- `validateChartConfig()` - Check if config is valid
|
||
- `renderChartBuilderPreview()` - Render preview with error handling
|
||
- `createSnippetFromBuilder()` - Generate and save snippet
|
||
- `closeChartBuilder()` - Close modal and cleanup
|
||
|
||
### Reuses From Existing Codebase
|
||
|
||
- `DatasetStorage.getDataset(id)` - Fetch dataset
|
||
- `resolveDatasetReferences(spec)` - Resolve data.name references
|
||
- `SnippetStorage.saveSnippet()` - Save new snippet
|
||
- `generateSnippetId()` / `generateSnippetName()` - Auto-generate IDs/names
|
||
- `selectSnippet(id)` - Open snippet in editor
|
||
- `URLState.update()` - Update URL state
|
||
- `showToast()` - User notifications
|
||
- `getSetting()` - Access user settings (debounce)
|
||
|
||
## Design Decisions
|
||
|
||
**Why Vega-Lite Compatible Schema?** - Direct mapping to output spec, no translation layer, easy to debug.
|
||
|
||
**Why Type Toggle Buttons?** - Matches existing UI (Draft/Published buttons), single-click interaction, visual clarity.
|
||
|
||
**Why Separate "Build Chart" from "New Snippet"?** - Different workflows (guided vs manual), both valid entry points.
|
||
|
||
**Why No Aggregations in v1?** - Keeps UI simple, most common use case is direct mapping, users can add in editor.
|
||
|
||
**Why Center Preview?** - Respects dimensions, consistent with main preview, allows scrolling for large charts.
|
||
|
||
## File Structure
|
||
|
||
**Files Modified:**
|
||
- `src/js/chart-builder.js` - NEW (~457 lines)
|
||
- `src/js/config.js` - URL state support for `/build` action
|
||
- `src/js/app.js` - URL handler for chart builder
|
||
- `src/styles.css` - Chart builder styles (lines 491-547)
|
||
- `index.html` - Chart builder modal HTML + "Build Chart" button
|
||
|
||
## Next Steps
|
||
|
||
1. ✅ Get approval on HTML/CSS frame - DONE
|
||
2. ✅ Implement chart-builder.js (core logic) - DONE
|
||
3. ✅ Refactor editor.js (reusable preview) - NOT NEEDED (reused existing functions)
|
||
4. ✅ Wire up integrations (dataset-manager.js, app.js) - DONE
|
||
5. **Test with real datasets** - READY FOR MANUAL TESTING
|
||
6. **Document in CHANGELOG.md** - TODO after testing
|
||
|
||
## Notes
|
||
|
||
- Performance: Debounced preview using existing render settings
|
||
- Error Handling: Shows inline error messages with helpful text
|
||
- Keyboard Support: ESC closes modal, Tab navigation
|
||
- URL State: Browser back/forward navigation integrated
|
||
- Dark Theme: Full support for experimental theme
|
||
|
||
## Future Enhancements
|
||
|
||
Potential improvements for future versions:
|
||
- Aggregations (count, sum, mean), transforms (filter, calculate)
|
||
- Layering, faceting, and composition
|
||
- Advanced mark properties, axis/legend customization
|
||
- Custom color schemes, saved templates
|
||
- Chart recommendations based on data types
|
||
|
||
---
|
||
|
||
**Document Status**: ✅ IMPLEMENTATION COMPLETE - Ready for Manual Testing
|
||
**Last Updated**: 2025-11-17
|
||
**Current Phase**: All Steps Complete - Chart Builder Fully Functional
|
||
|
||
## Summary of Completed Work
|
||
|
||
### ✅ Fully Functional Features:
|
||
- ✅ Complete modal UI with proper layout (1/3 config, 2/3 preview)
|
||
- ✅ Mark type toggle buttons (Bar/Line/Point/Area/Circle) - fully interactive
|
||
- ✅ Encoding sections with field dropdowns and type buttons (Q/O/N/T) - fully interactive
|
||
- ✅ Dimensions inputs (Width/Height) - functional with live preview
|
||
- ✅ Modal open/close functionality (Build Chart button, X, Cancel, Back, ESC)
|
||
- ✅ Proper styling without text clipping issues
|
||
- ✅ Dark theme support
|
||
- ✅ Dropdowns populated with dataset columns
|
||
- ✅ Interactive toggles for mark type and encoding types
|
||
- ✅ Vega-Lite spec generation from UI state
|
||
- ✅ Live preview with debounced rendering
|
||
- ✅ Validation and "Create Snippet" functionality
|
||
- ✅ URL state integration (#datasets/dataset-123/build)
|
||
- ✅ Browser back/forward navigation support
|
||
- ✅ Auto-defaults based on column types
|
||
- ✅ Error handling and validation messages
|
||
|
||
### Ready for Testing:
|
||
The chart builder is now feature-complete and ready for manual testing with real datasets. All core functionality has been implemented and integrated.
|