How elementCenter Calculates Click Coordinates in Ego-Lite
The elementCenter helper determines viewport-relative click coordinates by resolving the target selector, ensuring visibility via scroll operations, and computing the geometric center from the element's bounding box dimensions.
The elementCenter helper is a core utility in the citrolabs/ego-lite browser automation framework that enables precise interaction with DOM elements. According to the source code in package/ego-browser/src/driver/observe.ts, this function implements a three-stage pipeline to convert abstract selectors into concrete {x, y} coordinates suitable for Chrome DevTools Protocol (CDP) based pointer events.
Three-Stage Coordinate Resolution
The helper operates through a coordinated sequence defined across multiple source files, ensuring accurate positioning regardless of viewport state or selector type.
Element Resolution via element-resolver.ts
First, elementCenter resolves the input selector—which may be CSS, XPath, @ref, or loc=—to a concrete DOM node handle. This occurs through the shared element-resolver logic in src/element-resolver.ts. The resolver yields a JavaScript handle compatible with CDP evaluation, abstracting away the differences between selector syntaxes before any geometric calculations occur.
Viewport Alignment with scrollIntoView
Before measuring geometry, the helper ensures the target is visible. In src/driver/pointer.ts at line 562, the runtime injects a script that centers the element within the viewport:
if (typeof this.scrollIntoViewIfNeeded === 'function') {
this.scrollIntoViewIfNeeded(true);
} else {
this.scrollIntoView({ block: 'center', inline: 'center' });
}
This guarantees that subsequent coordinate calculations reference visible, viewport-relative positions rather than off-screen locations.
Geometric Center Computation
After scrolling, the helper executes a CDP-eval script (buildSelectorCenterJs) to retrieve the element’s bounding box properties: top, left, width, and height. The center point is computed using standard geometric formulas:
const cx = left + width / 2;
const cy = top + height / 2;
As implemented in src/driver/pointer.ts at line 627, these calculations run asynchronously via Promise.all, performing the top-left corner and center-point extractions in parallel to minimize latency.
CDP Integration and Async Execution
The elementCenter function leverages the Chrome DevTools Protocol to bridge JavaScript evaluation with browser automation. By utilizing CDP script injection for both the scroll operation and the bounding box extraction, the helper maintains precision across navigation events and dynamic page changes. The parallel execution model at line 627 of src/driver/pointer.ts ensures efficient coordination between element resolution and coordinate calculation.
Using elementCenter in Your Code
The public API is exposed as page.elementCenter(selector), documented in src/format.ts (lines 425-437) and injected into the helper context via src/helpers.ts at line 87. Here are practical usage patterns:
// Get centre coordinates of a CSS selector
const centre = await page.elementCenter('#submit-button');
console.log(centre); // => { x: 342.5, y: 218.0 }
// Direct click usage (internally calls elementCenter)
await page.click('#submit-button');
// Resolve reference-style selectors (e.g., @12)
const refCentre = await page.elementCenter('@12');
await page.click({ selector: '@12' });
Summary
- Selector Resolution: Converts CSS, XPath,
@ref, andloc=selectors to DOM handles viasrc/element-resolver.ts. - Visibility Guarantee: Centers elements in viewport using
scrollIntoViewIfNeededorscrollIntoView(line 562 ofsrc/driver/pointer.ts). - Geometric Calculation: Computes center as
left + width/2andtop + height/2from bounding box data. - Parallel Execution: Resolves and measures coordinates concurrently using
Promise.allat line 627 ofsrc/driver/pointer.ts. - Public API: Accessible via
page.elementCenter(), injected throughsrc/helpers.tsand documented insrc/format.ts.
Frequently Asked Questions
What selector types does elementCenter support?
The helper supports CSS selectors, XPath expressions, reference-style selectors prefixed with @ (e.g., @12), and location-based selectors using the loc= syntax. All types route through the shared resolver in src/element-resolver.ts before coordinate calculation begins.
Why does elementCenter scroll the element before calculating coordinates?
Scrolling ensures the element is within the visible viewport before measurement. This prevents coordinate calculations based on off-screen positions that would result in incorrect click locations or pointer events failing to hit the target element.
How does elementCenter handle elements with complex CSS transforms?
The helper relies on the browser's native getBoundingClientRect() via CDP evaluation to retrieve the final layout geometry. This returns the bounding box after all CSS transforms are applied, ensuring the calculated center point reflects the actual rendered position on screen.
Where is the coordinate calculation logic located in the source code?
The core calculation logic resides in src/driver/pointer.ts at lines 562 and 627, while the public API definition exists in src/driver/observe.ts. The injection into the runtime context occurs in src/helpers.ts at line 87.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →