> For the complete documentation index, see [llms.txt](https://docs.avonnicomponents.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.avonnicomponents.com/projects/flow-components/interactive-layouts/interactive-map-filtering.md).

# Interactive Map Filtering

### Overview

This tutorial walks you through building a Screen Flow in which a map and four metrics update in real time as the user pans or zooms. When the user moves the map, the visible records shrink or expand, and the metrics recalculate automatically to reflect what's on screen.

{% hint style="danger" %}

#### **Consider using Dynamic Components for this tutorial**

This tutorial still works, but building reactive map + metrics UIs is exactly what [**Dynamic Components**](broken://spaces/ODPvvv7Cx9Z9RECLn3oV/pages/P8PVbTIIkHp8MWRGbyzg) are designed for. In DC, the Map's `centerLatitude`, `centerLongitude`, and `visibleWidthKm` plug directly into a Query filter — no formula variable, no text concatenation, and the queries re-run automatically as the user moves the map. Keep the Flow version only when this UI has to live inside a Screen Flow process.

[**→ See the Dynamic Components**](broken://spaces/ODPvvv7Cx9Z9RECLn3oV/pages/P8PVbTIIkHp8MWRGbyzg)
{% endhint %}

***

### What You'll Build

A single-screen flow with:

* Four **Avonni Metric** components showing counts or sums for the visible area (for example: number of accounts, total revenue, number of active customers, average deal size).
* An **Avonni Map** displaying records pinned by location.
* Two Flow **formula variables** that act as live filters. Every time the user moves the map, the formulas recompute and the components re-query.

<figure><img src="/files/mab0qXhR1p6e1H67KMMc" alt=""><figcaption></figcaption></figure>

***

### Before You Start

You need one of the following data setups. The tutorial uses the first option because it works on any Salesforce org without creating custom fields.

| Data setup                                  | What to check                                                                                                                                                                                                                                                              |
| ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Standard Account with a billing address** | Your Accounts need populated **BillingStreet**, **BillingCity**, and **BillingCountry** — or directly populated **BillingLatitude** and **BillingLongitude**. Salesforce auto-populates the lat/long via a Data Integration Rule ("Geocodes for Account Billing Address"). |
| **Custom object with a Geolocation field**  | Your object needs a field of type **Geolocation** (compound lat/long).                                                                                                                                                                                                     |
| **Standard object with two Number fields**  | Your object has a **Latitude** and **Longitude** number field, each with up to 15 decimal places.                                                                                                                                                                          |

{% hint style="warning" %}

#### Important

The `DISTANCE()` SOQL function used in this tutorial requires a **compound** location field — either a Geolocation custom field or a standard compound address like `BillingAddress`. It does **not** work against two separate Number fields. If your setup uses two separate lat/long numbers, see Adapt to Your Own Data
{% endhint %}

The rest of the tutorial uses the standard **Account** object with its built-in **BillingAddress** compound field and **Industry** picklist.

***

{% stepper %}
{% step %}

#### Step 1 — Create the Screen Flow

1. In Setup, open **Flow** and click **New Flow**.
2. Select **Screen Flow**, then click **Create**.
3. Add a **Screen** element to the canvas.
4. Open the Screen element to start adding components.

Show Image

<figure><img src="/files/CWpbc55wZdqBrVDTTLM4" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}

#### Step 2 — Add a Four-Column Section for the Metrics

1. In the Screen element, drag a **Section** onto the canvas.
2. In the Section settings, set the layout to **Four columns**.

This row will hold the four Avonni Metric components side by side.

<figure><img src="/files/CWRGXvqEjHnH9YGW5EAn" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}

#### Step 3 — Configure the Four Metrics

Drag an **Avonni Metric** component into each of the four columns. Give each one a clear **API Name** so you can reference it later.

For every metric, do the following:

1. Open the **Component Builder** on the metric (click **Edit** on the component card).
2. In the **Properties** tab, set the **Label** — for example, `Total accounts in view`.
3. Expand the **Primary** section. This is where you configure the main metric value.
4. Set the **Format Style** to match what this metric displays:
   * **Decimal** — for counts or plain numbers (e.g., number of accounts, average employees).
   * **Currency** — for monetary values (e.g., total revenue).
   * **Percent** or **Percent Fixed** — for ratios and percentages.
   * **Date** — if the metric represents a date (e.g., most recent activity).
5. On the **Value** attribute, click the small icon on the right and select **Query**.
6. Choose the object — use **Account** for this tutorial.
7. Pick the **field** and **aggregate function** for that metric.
8. Optionally, add an **Avatar icon** from the Avatar section to give each metric a visual identifier.

Here's a suggested configuration for a realistic dashboard:

| Metric                 | Format Style | Aggregate | Field                            | Label                  |
| ---------------------- | ------------ | --------- | -------------------------------- | ---------------------- |
| Total accounts in view | Decimal      | `COUNT`   | `Id`                             | Total accounts in view |
| Total annual revenue   | Currency     | `SUM`     | `AnnualRevenue`                  | Revenue                |
| Active customer count  | Decimal      | `COUNT`   | `Id` + filter `Active__c = true` | Active                 |
| Average employee count | Decimal      | `AVG`     | `NumberOfEmployees`              | Avg. employees         |

> **Example:** A field sales rep drags the map over the Bay Area. The four metrics immediately show "47 Accounts", "$12.4M Revenue", "31 Active", "Avg. 218 employees" — all for the zone they're currently viewing

{% hint style="info" %}

#### **Leave the filter empty for now**

We'll add the dynamic filter in Step 5 once we've created the formula variables
{% endhint %}
{% endstep %}

{% step %}

#### Step 4 — Add and Configure the Map

Drag an **Avonni Map** component below the section.

1. In the **Properties** tab, set **Map Type** to **Leaflet Maps**.

   > **Important:** Google Maps does not report the visible viewport back to Flow. Only **Leaflet Maps** exposes `centerLatitude`, `centerLongitude`, and `visibleWidthKm` — the values we need for dynamic filtering.
2. In **Data Source**, choose **Query** and select the **Account** object.
3. In **Data Mappings**, connect:
   * **Latitude** → `BillingLatitude`
   * **Longitude** → `BillingLongitude`
4. Give the Map a clear **API Name** — this tutorial assumes `map`. The formulas in Step 5 reference this name exactly.

<figure><img src="/files/ddJ46c8gUkSEPug4VGSA" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}

#### Step 5 — Create the Dynamic Filter Formulas

This is the core of the tutorial. We'll create two **Flow formula variables** that produce a live SOQL filter clause. Each time the user moves the map, the formulas recompute and feed the Map and Metrics with a fresh filter.

<details>

<summary>How the Formula Works</summary>

The formula calculates a distance filter for each record's location relative to the map's current center, then compares that distance to the map's visible width. Records outside the visible area are excluded.

In SOQL terms, the formula builds this string at runtime:

`DISTANCE(BillingAddress, GEOLOCATION(<centerLat>, <centerLong>), 'km') < <visibleWidthKm>`

where `<centerLat>`, `<centerLong>`, and `<visibleWidthKm>` are pulled live from the map's output.

</details>

{% hint style="danger" %}

#### **Simpler using Avonni Dynamic Components**

The Map's `centerLatitude`, `centerLongitude`, and `visibleWidthKm` plug directly into a Query filter — no formula variable, no text concatenation.&#x20;

[**→ See the Dynamic Components**](broken://spaces/ODPvvv7Cx9Z9RECLn3oV/pages/P8PVbTIIkHp8MWRGbyzg)
{% endhint %}

#### Formula 1 — Map Filter

This formula controls which records appear as pins on the map.

1. In the Flow toolbox, create a new **Formula** resource.
2. Name it `VisibleAreaFilter`, with **Data Type** set to **Text**.
3. Paste this expression:

`"DISTANCE(BillingAddress, GEOLOCATION(" & {!map.centerLatitude} & "," & {!map.centerLongitude} & "), 'km') <" & TEXT({!map.visibleWidthKm})`&#x20;

<figure><img src="/files/0mwecCcTPoVQecx12a1W" alt=""><figcaption></figcaption></figure>

**What each piece does:**

| Piece                                                    | Purpose                                                                                              |
| -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `"DISTANCE(BillingAddress, GEOLOCATION("`                | Start of the SOQL clause. `BillingAddress` is the compound field containing the record's location.   |
| `& {!map.centerLatitude} & "," & {!map.centerLongitude}` | Injects the map's current center coordinates, live.                                                  |
| `& "), 'km') <"`                                         | Closes the GEOLOCATION and DISTANCE calls, units in kilometers.                                      |
| `& TEXT({!map.visibleWidthKm})`                          | Converts the map's current visible width (in km) to text and appends it as the comparison threshold. |

The `& "&"` syntax is standard Flow text concatenation — each `&` glues the surrounding pieces together, and `TEXT(…)` converts numbers to strings so they sit cleanly inside the SOQL string.

#### Formula 2 — Metric Filter

Some of your metrics show the **full visible population** — every Account on the map. These metrics can be reused `VisibleAreaFilter` as-is. But some metrics measure a **subset** of what's visible — only active customers, only a specific industry, only high-revenue accounts. For each subset, you need a separate formula that layers an extra SOQL condition on top of `VisibleAreaFilter`.

**When to create a segment filter:**

* ✅ Create one when the metric answers "how many of the visible records *also* match X condition?"
* ❌ Skip it when the metric answers "what's the total / count / average of everything visible?"

For the four metrics in this tutorial, here's how the mapping works:

| Metric                     | Needs a segment filter?          | Formula to use                     |
| -------------------------- | -------------------------------- | ---------------------------------- |
| **Total accounts in view** | No — counts everything visible   | `VisibleAreaFilter`                |
| **Total annual revenue**   | No — sums everything visible     | `VisibleAreaFilter`                |
| **Active customer count**  | Yes — only active accounts       | `MetricFilterActive` (new formula) |
| **Average employee count** | No — averages everything visible | `VisibleAreaFilter`                |

**Create the segment filter formula:**

1. In the Flow toolbox, create a new **Formula** resource.
2. Name it `MetricFilterActive`, with **Data Type** set to **Text**.
3. Paste:

`"DISTANCE(BillingAddress, GEOLOCATION(" & {!map.centerLatitude} & "," & {!map.centerLongitude} & "), 'km') <" & TEXT({!map.visibleWidthKm}) & " AND Active__c = true"`

The added `" AND Active__c = true"` at the end narrows results to active accounts only. The rest of the expression is identical to `VisibleAreaFilter` — same distance calculation, same visible-width comparison.

**Create one formula per segment you want to track:**

| Segment you want to measure      | Extra SOQL to append                                                   |
| -------------------------------- | ---------------------------------------------------------------------- |
| Active accounts                  | `AND Active__c = true`                                                 |
| Technology accounts              | `AND Industry = 'Technology'`                                          |
| Large accounts ($10M+)           | `AND AnnualRevenue > 10000000`                                         |
| Accounts with open opportunities | `AND Id IN (SELECT AccountId FROM Opportunity WHERE IsClosed = false)` |

> **Tip:** Keep formula names descriptive of the segment, not of the metric — `MetricFilterActive` is reusable across any metric counting active records, while `ActiveCustomerCountFilter` is not.

{% hint style="warning" %}

#### **Watch the quoting carefully**

SOQL string values (`'Technology'`) need single quotes inside the Flow text literal (`" AND Industry = 'Technology'"`). A missing or swapped quote will produce a `Cannot read properties of undefined` error at runtime because the filter string can't be parsed
{% endhint %}
{% endstep %}

{% step %}

#### Step 6 — Wire the Formulas as Mapped Filters

Connect each formula to the right Metric. The **Map itself doesn't need a filter** — Leaflet automatically displays only the pins inside the current viewport, and filtering the Map's query on top of that would break the user's ability to pan smoothly into adjacent areas.

**For each Metric:**

1. Open the Metric's **Component Builder**.
2. Expand the **Data Source** section inside the Primary value.
3. In the **Filter** field, click the toggle and choose **Mapped**.
4. Select the formula that matches the metric:

<table><thead><tr><th width="255.7734375">Metric</th><th>Formula to select</th></tr></thead><tbody><tr><td>Total accounts in view</td><td><code>VisibleAreaFilter</code></td></tr><tr><td>Total annual revenue</td><td><code>VisibleAreaFilter</code></td></tr><tr><td>Active customer count</td><td><code>MetricFilterActive</code></td></tr><tr><td>Average employee count</td><td><code>VisibleAreaFilter</code></td></tr></tbody></table>

<figure><img src="/files/fbfKvrIGYfocDcCipd2l" alt=""><figcaption></figcaption></figure>

> **Tip:** If you need a Metric to count only what's on screen, use `VisibleAreaFilter`. If you need a Metric to count a **segment** of what's on screen (only active, only a specific industry), use the dedicated segment filter you created in Step 5.

{% hint style="warning" %}

#### **Don't apply these filters to the Map component**

The Map's own Query should remain unfiltered (or use a broader business filter like "Accounts in North America"). Filtering the Map by visible area creates a blank-canvas effect whenever the user pans — records in the new area haven't been queried yet
{% endhint %}
{% endstep %}

{% step %}

#### Step 7 — Test the Flow

1. Save and debug the flow.
2. When the flow opens, the map should load with all Account pins visible.
3. Zoom in or pan the map. The pins should be reduced to only those within the visible area, and the four metrics should update.
4. Zoom back out — pins and metrics should expand to match.

> **Tip:** If the metrics show zero at first and only update after you interact with the map, that's normal — `centerLatitude` and `centerLongitude` populate once the map has rendered its first view.
> {% endstep %}
> {% endstepper %}

***

### Adapt to Your Own Data

The tutorial uses Account.BillingAddress and Industry because every Salesforce org has them. If you want to use your own object or custom fields, here's what to change.

#### If Your Object Uses a Custom Geolocation Field

Replace `BillingAddress` in both formulas with your field's API name.

> **Example:** A `Store__c` custom object with a `StoreLocation__c` Geolocation field:
>
> `"DISTANCE(StoreLocation__c, GEOLOCATION(" & {!map.centerLatitude} & "," & {!map.centerLongitude} & "), 'km') <" & TEXT({!map.visibleWidthKm})`

Make sure:

* The field type in Setup is **Geolocation** (not two separate Number fields).
* You select **Decimal** coordinates with sufficient precision (at least 5 decimal places).

#### If Your Object Has Only Two Separate Lat/Long Number Fields

`DISTANCE()` in SOQL does not accept two separate numeric fields. You have two options:

* **Preferred:** Add a Geolocation custom field to your object, and populate it from your existing lat/long fields (for example, via a Flow, a Batch Apex job, or a Data Loader update).
* **Alternative:** Replace `DISTANCE()` with a bounding-box filter. Instead of a radius check, filter records where latitude is between *centerLat − visibleWidthKm÷111* and *centerLat + visibleWidthKm÷111*, and longitude similarly. This is less accurate at the poles but doesn't require a Geolocation field.

#### If Your Addresses Don't Have Lat/Long Values Yet

Salesforce can auto-geocode standard address fields. To enable it:

1. Go to **Setup → Data Integration Rules**.
2. Activate **Geocodes for Account Billing Address** (or the equivalent rule for your object).
3. Click **Edit Rule Settings**, then **Run Rule Now** to backfill existing records.

Once the rule runs, `BillingLatitude` and `BillingLongitude` populate automatically on every record whose address Salesforce can resolve.

#### If You Want the Metrics to Show Something Other Than Account Data

Swap two things in each Metric's configuration:

1. In the Metric's **Data Source**, change the queried object.
2. Update the corresponding formula variable's SOQL fragment to use the new object's location field. Remember that `DISTANCE()` only works on **that object's** geolocation field, so the Map and the Metrics must query objects that both have location fields — or you'll need separate formulas per object.

{% hint style="info" %}

#### **Why does the metric sometimes count more accounts than visible pins?**&#x20;

The metric uses a circular radius based on the map's visible width. A few accounts just outside the visible rectangle may fall inside that circle. Pan or zoom out to see them appear.
{% endhint %}

***

### Troubleshooting

| Problem                                                                | Cause                                                                                                                                                                     | Fix                                                                                                                                                                                                         |
| ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Map loads but no pins appear**                                       | `BillingLatitude`/`BillingLongitude` are empty on your Accounts.                                                                                                          | Activate the Data Integration Rule **Geocodes for Account Billing Address** in Setup and run the backfill.                                                                                                  |
| **Metrics show zero when the flow opens**                              | The map hasn't published `centerLatitude`/`centerLongitude` yet — the formula evaluates against null on the first render.                                                 | Normal behavior. Interact with the map once (pan or zoom) to trigger the first recalculation. If this is a problem, wrap the formula in an `IF` that returns a default filter when the map center is empty. |
| **`Cannot read properties of undefined (reading 'match')` at runtime** | The formula produced an incomplete SOQL string — usually caused by a missing quote, a trailing `&`, or a reference to a map property that doesn't exist (wrong API name). | Copy the formula exactly from this tutorial, double-check the map's API Name matches the name used in the formula, and verify every `&` has text on both sides.                                             |
| **The filter works for the Map but not the Metric**                    | The Metric is using the wrong formula — it's pointing at `VisibleAreaFilter` instead of `MetricFilterTechnology` (or vice versa).                                         | In the Metric's Component Builder, confirm **Data Source → Filter → Mapped** points to the formula with the extra `AND ...` condition you want.                                                             |
| **Setting Map Type to Google Maps breaks everything**                  | Google Maps does not expose `centerLatitude`, `centerLongitude`, or `visibleWidthKm` back to Flow.                                                                        | Switch to **Leaflet Maps** in the Map's Properties tab. This tutorial only works with Leaflet.                                                                                                              |
| **Pins appear but the metric count doesn't match the visible pins**    | The Metric formula has a different `AND` clause than the Map formula — that's expected if you want the metric to count a subset (like only Technology accounts).          | To have the metric exactly match the visible pins, reuse `VisibleAreaFilter` instead of a custom one.                                                                                                       |
| **Metric count higher than visible pins**                              | The radius filter is circular, the viewport is rectangular                                                                                                                | Expected behavior — pan/zoom to reveal the extra accounts, or divide `visibleWidthKm` by 2 in the formulas for a tighter match                                                                              |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.avonnicomponents.com/projects/flow-components/interactive-layouts/interactive-map-filtering.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
