@rtstic.dev/ascent-floorplan
v1.0.8
Published
A lightweight front-end package for ascent project.
Readme
Interactive Floorplan System
A comprehensive JavaScript-based system for managing interactive SVG floorplans with CMS integration, URL-based navigation, and dynamic unit selection.
Table of Contents
- Overview
- File Structure
- Architecture
- Data Flow
- Core Components
- Initialization Sequence
- HTML Requirements
- CSS Selectors & Classes
- URL Query Parameters
- API Reference
Overview
This system creates an interactive floorplan interface where users can:
- View units organized by bedroom types (tabs)
- Click units on an SVG floorplan to see details
- Navigate via URL parameters (deep linking)
- See sold/available status for each unit
- Auto-scroll to unit details when selected
File Structure
├── floorplan.js # Main logic and orchestration
├── featured-floorplan.js # CMS data collector & link updater
└── floorplan.css # Styling for interactive statesFile Responsibilities
floorplan.js (Main Controller)
- Loads SVG floorplan from CDN
- Collects data from SVG and CMS
- Manages tab navigation
- Handles unit selection
- URL query parameter management
- Browser history integration
featured-floorplan.js (CMS Helper)
- Collects unit data from CMS elements
- Updates card links with proper URLs
- Exposes utility methods via
window.CMSCollector
floorplan.css (Visual States)
- Active/inactive tab styles
- Selected unit highlighting
- Sold unit styling
- Detail panel visibility
Architecture
Data Sources
The system merges data from two sources:
- SVG Data - Extracted from the floorplan SVG structure
- CMS Data - Extracted from HTML elements with
data-fp-*attributes
These are combined into a Master Data Array that powers the entire interface.
Three Data Collections
window.floorplanDataFromSVG // Array of units from SVG
window.floorplanDataFromCMS // Array of units from CMS
window.masterFloorplanData // Merged + validated arrayData Flow
1. DOM Ready
↓
2. Load SVG from CDN
↓
3. Collect SVG Data (collectUnitDataFromSVG)
↓
4. Collect CMS Data (collectUnitDataFromCMS)
↓
5. Build Master Data (buildMasterFloorplanData)
↓
6. Initialize Tabs (initFloorPlanTabs)
↓
7. Read URL Query Params
↓
8. Set Active Tab from URL or Default
↓
9. Set Active Residence from URL (if present)
↓
10. Mark Sold Units (initializeSoldResidentsFromCMS)
↓
11. Attach Click Handlers (consoleSVGs)Core Components
1. URL Query Parameter System
The system uses two query parameters for deep linking:
?tab=<groupName>- Sets active bedroom type?residence=<unitId>- Selects specific unit
Functions:
updateTabQuery(tabValue)- Updates tab in URLgetTabFromQuery()- Reads tab from URLupdateResidenceQuery(id)- Updates residence in URLgetResidenceFromQuery()- Reads residence from URL
Example URLs:
# Default tab (1 BEDROOM + DEN)
/summit/floorplan
# Specific tab
/summit/floorplan?tab=2%20BEDROOM%20%2B%20DEN%20%2B%203%20BATH
# Tab with unit selection
/summit/floorplan?tab=1%20BEDROOM%20%2B%20DEN&residence=A_12092. Tab System
HTML Structure Required:
<div data-fp-tablink="1 BEDROOM + DEN" data-fp-tablink-active="false">
1 Bedroom + Den
</div>
<div data-fp-tablink="2 BEDROOM" data-fp-tablink-active="false">
2 Bedroom
</div>Behavior:
- Clicking a tab sets it as active
- Updates URL query parameter
- Highlights corresponding group in SVG
- Resets any selected residence
Key Functions:
initFloorPlanTabs()- Attaches click handlers to all tabssetActiveTab(tabValue)- Activates a specific tab
3. Unit Selection System
Selection Flow:
User clicks unit (SVG or CMS card)
↓
Find matching master data by ID
↓
Highlight unit in SVG (add 'selected' class)
↓
Show detail panel for that unit
↓
Update URL with residence ID
↓
Scroll to detail sectionKey Functions:
setActiveResidence(masterOrId)- Main selection orchestratorsetSelectedResidenceSVG(el)- Highlights unit in SVGshowSelectedResidenceDetail(id)- Shows detail panel
4. Data Collection
SVG Data Collection (collectUnitDataFromSVG)
Looks for:
<g class="unit clickable" id="unit-205" data-name="Unit 205">
<!-- Inside a parent group -->
<g class="unit-group" data-name="2 BEDROOM" id="group-2bed">
<!-- unit here -->
</g>
</g>Extracts:
{
id: "A_1209",
Name: "A 1209",
isSold: false, // from 'sold' class
groupName: "1 BEDROOM + DEN",
groupId: "_1_BEDROOM_DEN"
}Example from window.floorplanDataFromSVG:
[
{
"id": "S_2109",
"Name": "S 2109",
"isSold": false,
"groupName": "3 BEDROOM + DEN",
"groupId": "_3_BEDROOM_DEN"
},
{
"id": "A_1209",
"Name": "A 1209",
"isSold": false,
"groupName": "1 BEDROOM + DEN",
"groupId": "_1_BEDROOM_DEN"
}
// ... more units
]CMS Data Collection (collectUnitDataFromCMS)
Looks for:
<div data-fp-id="unit-205"
data-fp-name="Unit 205"
data-fp-group-name="2 BEDROOM"
data-fp-project="Summit Tower"
data-fp-soldout="false">
</div>Extracts:
{
id: "A_1209",
dataName: "1209",
groupName: "1 BEDROOM + DEN",
project: "Summit floor plans",
isSold: true
}Example from window.floorplanDataFromCMS:
[
{
"dataName": "1209",
"groupName": "1 BEDROOM + DEN",
"project": "Summit floor plans",
"id": "A_1209",
"isSold": true
},
{
"dataName": "2309",
"groupName": "1 BEDROOM + DEN",
"project": "Summit floor plans",
"id": "T_2309",
"isSold": true
}
// ... more units
]5. Master Data Building (buildMasterFloorplanData)
Merges SVG and CMS data with validation:
Validation Checks:
- IDs present in SVG but not CMS → Warning
- IDs present in CMS but not SVG → Warning
- Mismatched group names between sources → Warning
- Missing DOM elements for IDs → Warning
Output Structure:
{
id: "A_1209",
isSold: true,
groupName: "1 BEDROOM + DEN",
floorPlanEl: <g element>, // Direct reference to DOM node
dataFromSVG: { /* SVG data */ },
dataFromCMS: { /* CMS data */ }
}Example from window.masterFloorplanData:
[
{
"id": "A_1209",
"isSold": true,
"groupName": "1 BEDROOM + DEN",
"floorPlanEl": {}, // DOM element reference
"dataFromSVG": {
"id": "A_1209",
"Name": "A 1209",
"isSold": false,
"groupName": "1 BEDROOM + DEN",
"groupId": "_1_BEDROOM_DEN"
},
"dataFromCMS": {
"dataName": "1209",
"groupName": "1 BEDROOM + DEN",
"project": "Summit floor plans",
"id": "A_1209",
"isSold": true
}
},
{
"id": "C_1303",
"isSold": true,
"groupName": "2 BEDROOM + DEN + 3 BATH",
"floorPlanEl": {},
"dataFromSVG": {
"id": "C_1303",
"Name": "C 1303",
"isSold": false,
"groupName": "2 BEDROOM + DEN + 3 BATH",
"groupId": "_2_BEDROOM_DEN_3_BATH"
},
"dataFromCMS": {
"dataName": "1303",
"groupName": "2 BEDROOM + DEN + 3 BATH",
"project": "Summit floor plans",
"id": "C_1303",
"isSold": true
}
}
// ... more units
]Key Points:
isSoldat the top level comes from CMS (authoritative source)floorPlanElis a live DOM reference for direct manipulation- Both source data objects are preserved for debugging
6. Click Handler System (consoleSVGs)
Attaches click handlers to:
- All SVG units with class
clickable - All CMS elements with
[data-fp-id]
On Click:
- Finds matching data in all three collections
- Sets active residence
- Sets active tab (if group found)
- Logs data to console for debugging
7. Detail Panel System
HTML Structure Required:
<div data-fp-detail="unit-205" data-fp-detail-selected="false">
<!-- Unit details content -->
</div>
<!-- Scroll anchor -->
<div data-fp-detail-section-anchor></div>Behavior:
- Only one detail panel visible at a time
- Auto-scrolls to anchor when unit selected
- Smooth scroll animation (200ms delay for layout)
8. Sold Status System
Initialization Flow:
1. Remove 'sold' class from all units
2. Loop through masterFloorplanData
3. For each unit where isSold === true
4. Add 'sold' class to floorPlanElVisual Effect:
CSS automatically styles .unit.sold elements
Initialization Sequence
Step-by-Step on Page Load
// 1. DOM Ready Event
document.addEventListener('DOMContentLoaded', () => {
loadFloorPlan();
});
// 2. Load SVG from CDN
fetch(floorPlanSvg)
.then(res => res.text())
.then(svg => {
// 3. Inject SVG into #floorplan container
document.getElementById('floorplan').innerHTML = svg;
// 4. Wait 200ms for SVG to render
setTimeout(() => {
// 5. Collect all data
window.floorplanDataFromSVG = collectUnitDataFromSVG();
window.floorplanDataFromCMS = collectUnitDataFromCMS();
window.masterFloorplanData = buildMasterFloorplanData();
// 6. Attach click handlers
consoleSVGs();
// 7. Initialize tabs
initFloorPlanTabs();
// 8. Restore state from URL (200ms delay)
initActiveTabFromQuery({
delayMs: 200,
fallback: '1 BEDROOM + DEN'
});
initActiveResidenceFromQuery({ delayMs: 200 });
// 9. Apply sold status styling
initializeSoldResidentsFromCMS();
}, 200);
});Timing Delays Explained:
- 200ms after SVG injection: Allows browser to parse SVG DOM
- 200ms for URL query init: Ensures tabs are ready before activation
- Uses
setTimeoutto avoid race conditions
HTML Requirements
1. SVG Container
<div id="floorplan"></div>Purpose: Target for SVG injection from CDN
2. Tab Links
<div data-fp-tablink="1 BEDROOM + DEN"
data-fp-tablink-active="false">
1 Bedroom + Den
</div>
<div data-fp-tablink="2 BEDROOM + DEN + 3 BATH"
data-fp-tablink-active="false">
2 Bedroom + Den + 3 Bath
</div>
<div data-fp-tablink="3 BEDROOM + DEN"
data-fp-tablink-active="false">
3 Bedroom + Den
</div>Attributes:
data-fp-tablink- Group name (must match SVG and CMS exactly)data-fp-tablink-active- Managed by script ("true" | "false")
3. CMS Unit Cards
<div data-fp-id="A_1209"
data-fp-name="1209"
data-fp-group-name="1 BEDROOM + DEN"
data-fp-project="Summit floor plans"
data-fp-soldout="true">
<!-- Card content -->
</div>Attributes:
data-fp-id- Unique unit identifier (must match SVG exactly, e.g., "A_1209")data-fp-name- Display name (e.g., "1209")data-fp-group-name- Bedroom type (must match tab exactly)data-fp-project- Project namedata-fp-soldout- Must be lowercase "true" or "false"
4. Unit Detail Panels
<div data-fp-detail="A_1209"
data-fp-detail-selected="false">
<!-- Detail content -->
</div>Attributes:
data-fp-detail- Unit ID to match (e.g., "A_1209")data-fp-detail-selected- Managed by script ("true" | "false")
5. Detail Section Anchor
<div data-fp-detail-section-anchor></div>Purpose: Scroll target when unit is selected
6. Card Links (Optional - for featured-floorplan.js)
<a href="#" data-fp-card-link="A_1209">View Details</a>Purpose: Automatically updated with proper detail page URLs by featured-floorplan.js
CSS Selectors & Classes
Managed by JavaScript
| Selector | Added By | Purpose |
|----------|----------|---------|
| .clickable | Manual in SVG | Makes unit clickable |
| .unit | Manual in SVG | Identifies unit element |
| .unit-group | Manual in SVG | Groups units by type |
| .sold | Script | Marks sold units |
| .selected | Script | Highlights selected unit |
| .active | Script | Highlights active group |
Attribute Selectors
| Attribute | Values | Purpose |
|-----------|--------|---------|
| [data-fp-tablink-active] | "true" | "false" | Active tab styling |
| [data-fp-selected] | "true" | "false" | Selected group card |
| [data-fp-detail-selected] | "true" | "false" | Visible detail panel |
CSS Rules (from floorplan.css)
/* Active tab background */
[data-fp-tablink-active="true"] {
background-color: #d6bdac;
}
/* Sold unit styling */
svg .unit.sold polygon,
svg .unit.sold polyline {
fill: #ac3833 !important;
}
/* Selected unit highlight */
svg .unit.selected polygon,
svg .unit.selected polyline {
fill: #ad7c59 !important;
}
/* Active group highlight */
svg .unit-group.active .unit polygon {
fill: #d6bdac;
}
/* Detail panel visibility */
[data-fp-detail-selected="true"] {
display: block;
}
[data-fp-detail-selected="false"] {
display: none;
}URL Query Parameters
Structure
/summit/floorplan?tab=<groupName>&residence=<unitId>Examples
# Just tab selection
/summit/floorplan?tab=2%20BEDROOM%20%2B%20DEN%20%2B%203%20BATH
# Tab + unit selection
/summit/floorplan?tab=1%20BEDROOM%20%2B%20DEN&residence=A_1209
# No parameters (uses default: "1 BEDROOM + DEN")
/summit/floorplanBrowser History Integration
Forward/Back Button Support:
window.addEventListener('popstate', () => {
// Restore tab from URL
const fromTabQS = getTabFromQuery();
if (fromTabQS) setActiveTab(fromTabQS);
// Restore residence from URL
const fromResQS = getResidenceFromQuery();
if (fromResQS && Array.isArray(window.masterFloorplanData)) {
const master = window.masterFloorplanData.find(m => m.id === fromResQS);
if (master) setActiveResidence(master, { updateQS: false });
}
});Update Behavior:
replace: true- Replaces current history entry (default)replace: false- Pushes new history entry
API Reference
Global Objects
window.floorplanDataFromSVG
Array of unit data extracted from SVG structure.
window.floorplanDataFromCMS
Array of unit data extracted from CMS elements.
window.masterFloorplanData
Master array combining SVG and CMS data with DOM references.
window.CMSCollector (from featured-floorplan.js)
{
collect: collectUnitDataFromCMS,
log: logCmsDataAsJson,
updateFloorplanUrls: updateFloorplanUrls
}Core Functions
Selection Functions
setActiveResidence(masterOrId, options)
- Parameters:
masterOrId- Master object or unit ID stringoptions.updateQS- Update URL query (default: true)
- Purpose: Selects and displays a unit
setSelectedResidenceSVG(element)
- Parameters: DOM element (
<g>) - Purpose: Highlights unit in SVG
showSelectedResidenceDetail(id)
- Parameters: Unit ID string
- Purpose: Shows detail panel and scrolls to it
resetActiveResidences()
- Purpose: Clears all unit selections
Tab Functions
setActiveTab(tabValue)
- Parameters: Tab name string
- Purpose: Activates a tab and updates UI
initFloorPlanTabs()
- Purpose: Attaches click handlers to all tabs
Group Functions
setActiveGroupSVG(groupName)
- Parameters: Group name string
- Purpose: Adds 'active' class to matching SVG group
highlightActiveGroup(groupName)
- Parameters: Group name string
- Purpose: Updates
data-fp-selectedon CMS cards
Data Collection Functions
collectUnitDataFromSVG()
- Returns: Array of unit objects from SVG
- Purpose: Extracts unit data from loaded SVG
collectUnitDataFromCMS()
- Returns: Array of unit objects from CMS
- Purpose: Extracts unit data from HTML attributes
buildMasterFloorplanData()
- Returns: Master array with merged data
- Purpose: Combines and validates SVG + CMS data
URL Functions
updateTabQuery(tabValue, options)
- Parameters: Tab name, options object
- Purpose: Updates URL with tab parameter
getTabFromQuery()
- Returns: Tab name or null
- Purpose: Reads tab from URL
updateResidenceQuery(id, options)
- Parameters: Unit ID, options object
- Purpose: Updates URL with residence parameter
getResidenceFromQuery()
- Returns: Unit ID or null
- Purpose: Reads residence from URL
initActiveTabFromQuery(options)
- Parameters:
{ delayMs, fallback } - Purpose: Restores tab from URL on page load
initActiveResidenceFromQuery(options)
- Parameters:
{ delayMs } - Purpose: Restores unit selection from URL
Initialization Functions
loadFloorPlan()
- Purpose: Main initialization function
- Triggers: Full data collection and setup sequence
initializeSoldResidentsFromCMS()
- Purpose: Applies 'sold' class to units based on CMS data
consoleSVGs()
- Purpose: Attaches click handlers and console logging
Common Patterns
Adding a New Unit
In SVG:
<g class="unit-group" data-name="2 BEDROOM + DEN + 3 BATH" id="_2_BEDROOM_DEN_3_BATH"> <g class="unit clickable" id="C_2306" data-name="C 2306"> <!-- polygon/polyline shapes --> </g> </g>In CMS:
<div data-fp-id="C_2306" data-fp-name="2306" data-fp-group-name="2 BEDROOM + DEN + 3 BATH" data-fp-project="Summit floor plans" data-fp-soldout="false"> </div>Detail Panel:
<div data-fp-detail="C_2306" data-fp-detail-selected="false"> <!-- content --> </div>
Important: IDs must match exactly across all three locations (SVG, CMS, detail panel).
Marking a Unit as Sold
Update CMS attribute:
<div data-fp-id="C_2306" data-fp-soldout="true">Script will automatically:
- Parse the boolean attribute (must be lowercase "true")
- Add 'sold' class to SVG element
- Apply red styling from CSS
Example of sold units:
A_1209- Sold (1 BEDROOM + DEN)C_2306- Sold (2 BEDROOM + DEN + 3 BATH)B3_1208- Sold (2 BEDROOM + DEN + 2.5 BATH)
Adding a New Bedroom Type (Tab)
Add tab link:
<div data-fp-tablink="STUDIO" data-fp-tablink-active="false"> Studio </div>Update SVG with matching group:
<g class="unit-group" data-name="STUDIO" id="_STUDIO"> <!-- units --> </g>Update CMS cards:
<div data-fp-group-name="STUDIO" ...>
Note: Group names are case-sensitive and must match exactly everywhere.
Debugging
Check collected data:
console.log(window.floorplanDataFromSVG);
console.log(window.floorplanDataFromCMS);
console.log(window.masterFloorplanData);Manual control:
// Select a unit manually
setActiveResidence('A_1209');
// Switch tabs manually
setActiveTab('2 BEDROOM + DEN + 3 BATH');
// Reset selections
resetActiveResidences();featured-floorplan.js Extension
Purpose
Collects CMS data and updates card link URLs with proper query parameters.
Key Features
Data Collection:
window.CMSCollector.collect()URL Building:
// Builds: /summit/floorplan?tab=1%20BEDROOM%20%2B%20DEN&residence=A_1209 buildDetailSlug(groupName, id)Link Updates:
// Updates all [data-fp-card-link] hrefs window.CMSCollector.updateFloorplanUrls(data)
Auto-Execution
Runs automatically on DOMContentLoaded or immediately if DOM is ready.
Configuration
const DETAIL_BASE_PATH = "/summit/floorplan"; // Adjust as neededTroubleshooting
Issue: Units not clickable
- Check for
.clickableclass on<g>elements in SVG - Verify
consoleSVGs()was called after SVG load
Issue: Data mismatch warnings
- Ensure IDs match exactly between SVG and CMS
- Check group names are identical (case-sensitive)
- Verify all required
data-fp-*attributes present
Issue: Details not showing
- Check
[data-fp-detail]matches unit ID exactly - Verify detail section has anchor element
- Check CSS
displayrules for selected state
Issue: URL parameters not working
- Verify 200ms delay in initialization functions
- Check browser history state on back/forward
- Ensure tab/residence values are URL-encoded properly
Issue: Sold status not applying
- Confirm
data-fp-soldoutis lowercase "true"/"false" - Check
initializeSoldResidentsFromCMS()runs after data build - Verify CSS
.soldrules are present
License & Credits
SVG Source: Picked from this repository.
const floorPlanSvg = "https://cdn.jsdelivr.net/npm/@rtstic.dev/[email protected]/dist/floorplan.svg";Last Updated: 22 October 2025
