How to Show Customers on a Map with Popups in Oracle APEX

Add coordinates to customers, create a map page with the wizard, and show each customer's city and orders in a popup.

A list of customers does not show where they are. On a map, a sales team sees at a glance which regions have many customers, which have few, and which customers are close to each other. Clicking a marker should show the customer's details without leaving the map.

Oracle APEX has a Map region that draws points from latitude and longitude columns, with tooltips, popups, and zoom, and no JavaScript. This guide adds coordinates to customers, creates a map page with the wizard, and adds a popup with the customer's city and number of orders.

Controlling a map from JavaScript is a separate topic, covered in How to Control Map Layers, Features, and Popups Using JavaScript in Oracle APEX.

Step 1: The Tables

Customers belong to cities, cities to states, and states to countries:

Example:

create table countries (
    country_id number generated by default as identity primary key,
    name       varchar2(60) not null unique
);

create table states (
    state_id   number generated by default as identity primary key,
    country_id number not null references countries,
    name       varchar2(60) not null
);

create table cities (
    city_id  number generated by default as identity primary key,
    state_id number not null references states,
    name     varchar2(60) not null
);

create table customers (
    customer_id   number generated by default as identity primary key,
    name          varchar2(100) not null,
    email         varchar2(120) not null,
    customer_type varchar2(10) default 'PERSON' not null
                  constraint customers_type_ck check (customer_type in ('PERSON', 'COMPANY')),
    company_name  varchar2(100),
    tax_id        varchar2(30),
    country_id    number references countries,
    state_id      number references states,
    city_id       number references cities,
    created_at    date default sysdate not null
);

The map needs a position for each customer. Add LATITUDE and LONGITUDE columns with check constraints for the valid ranges, fill the cities with their real coordinates, and place each customer near the center of their city:

Example:

alter table cities add (
    latitude  number(9, 6)
              constraint cities_latitude_ck check (latitude between -90 and 90),
    longitude number(9, 6)
              constraint cities_longitude_ck check (longitude between -180 and 180)
);

alter table customers add (
    latitude  number(9, 6)
              constraint customers_latitude_ck check (latitude between -90 and 90),
    longitude number(9, 6)
              constraint customers_longitude_ck check (longitude between -180 and 180)
);

merge into cities c
using (select 'Mumbai' as name, 19.0760 as lat, 72.8777 as lon from dual union all
       select 'Pune',           18.5204,  73.8567 from dual union all
       select 'Nagpur',         21.1458,  79.0882 from dual union all
       select 'Bengaluru',      12.9716,  77.5946 from dual union all
       select 'Mysuru',         12.2958,  76.6394 from dual union all
       select 'New Delhi',      28.6139,  77.2090 from dual union all
       select 'Los Angeles',    34.0522, -118.2437 from dual union all
       select 'San Francisco',  37.7749, -122.4194 from dual union all
       select 'Austin',         30.2672,  -97.7431 from dual union all
       select 'Houston',        29.7604,  -95.3698 from dual union all
       select 'New York City',  40.7128,  -74.0060 from dual union all
       select 'Buffalo',        42.8864,  -78.8784 from dual union all
       select 'Munich',         48.1351,   11.5820 from dual union all
       select 'Nuremberg',      49.4521,   11.0767 from dual union all
       select 'Berlin',         52.5200,   13.4050 from dual union all
       select 'Sao Paulo',     -23.5505,  -46.6333 from dual union all
       select 'Campinas',      -22.9099,  -47.0626 from dual union all
       select 'Salvador',      -12.9777,  -38.5016 from dual) s
on (c.name = s.name)
when matched then update set c.latitude = s.lat, c.longitude = s.lon;

update customers cu
set    (latitude, longitude) =
       (select ci.latitude  + (mod(cu.customer_id, 5) - 2) * 0.02,
               ci.longitude + (mod(cu.customer_id, 3) - 1) * 0.02
        from   cities ci
        where  ci.city_id = cu.city_id)
where  cu.city_id is not null;

commit;

select cu.customer_id, cu.name, ci.name as city, cu.latitude, cu.longitude
from   customers cu
left join cities ci on ci.city_id = cu.city_id
order by cu.customer_id
fetch first 6 rows only;

Output:

Table CITIES altered.

Table CUSTOMERS altered.

18 rows merged.

41 rows updated.

Commit complete.

   CUSTOMER_ID NAME          CITY              LATITUDE    LONGITUDE
______________ _____________ ______________ ___________ ____________
             1 Customer 1    Pune               18.5004      73.8567
             2 Customer 2    Nagpur             21.1458      79.1082
             3 Contact 3     Bengaluru          12.9916      77.5746
             4 Customer 4    Mysuru             12.3358      76.6394
             5 Customer 5    New Delhi          28.5739       77.229
             6 Contact 6     Los Angeles        34.0322    -118.2637

6 rows selected.

The small offsets by customer ID keep customers of the same city from sitting on the same point. In a real application, the coordinates come from the customer's address, for example from a geocoding service.

Step 2: Create the Map Page

In App Builder, click Create Page, and on the Component tab click Map:

Create a Page wizard with the Map tile marked with a red box
The Map page type.

Enter Page Number 210 and Name Customer Map, and set Source Type to SQL Query:

Create Map wizard with Page Number 210, Name Customer Map and Source Type SQL Query marked with red boxes
The page and its data source.

Enter this query. It returns each customer with the city name and the number of orders, which the popup will show:

Example:

select cu.customer_id,
       cu.name,
       ci.name as city,
       cu.latitude,
       cu.longitude,
       (select count(*) from orders o where o.customer_id = cu.customer_id) as orders
from   customers cu
left join cities ci on ci.city_id = cu.city_id
where  cu.latitude is not null
Create Map wizard with the SQL query on CUSTOMERS and CITIES marked with a red box, Use Breadcrumb off and Use Navigation on
The query of the map layer.

Turn off Use Breadcrumb, keep Use Navigation on, and click Next. In the Map Style step, choose Points, set Geometry Column Type to Two Numeric Columns, Longitude Column LONGITUDE, Latitude Column LATITUDE, and Tooltip Column NAME:

Create Map wizard step Map Style with Points selected, Geometry Column Type Two Numeric Columns, Longitude Column LONGITUDE, Latitude Column LATITUDE and Tooltip Column NAME marked with red boxes
Points from the two coordinate columns.

Two Numeric Columns is the choice for plain latitude and longitude columns; Geometry Column is for SDO_GEOMETRY columns of Oracle Spatial. Click Create Page.

Step 3: Name the Layer and Set Its Key

The wizard creates a Map region with one layer, both named Customer Map. In Page Designer, select the layer under Layers. Set Name to Customers, the label of the layer in the map's legend, and in Column Mapping set Primary Key Column to CUSTOMER_ID, so each point is identified by its customer:

Page Designer showing the map layer with Name Customers, Layer Type Points, Geometry Column Data Type Longitude/Latitude, Longitude Column LONGITUDE, Latitude Column LATITUDE and Primary Key Column CUSTOMER_ID marked with red boxes
The layer's name and column mapping.

In the Appearance group, set Fill Color to #1E6FA8 for the markers. The Tooltip Column NAME from the wizard shows the customer's name when the mouse is over a marker:

Page Designer showing the layer Appearance Fill Color #1e6fa8 and Tooltip Column NAME marked with red boxes
Marker color and tooltip.

Step 4: Add the Popup

In the Info Window group, turn on Advanced Formatting and enter this HTML Expression. The substitutions &NAME., &CITY., and &ORDERS. are the columns of the layer's query:

Example:

<strong>&NAME.</strong><br>&CITY.<br>Orders: &ORDERS.
Page Designer showing the layer Info Window with Advanced Formatting on and the HTML Expression marked with red boxes
The content of the popup.

Click Save.

Step 5: Test It

DEMO_DEV opened Customer Map. APEX zoomed the map to show all 41 customers with coordinates, in India, the United States, Germany, and Brazil, with the legend entry Customers below the map:

Oracle APEX Customer Map with blue markers for customers in North America, South America, Europe and India
All customers on one map.

Zooming in on Berlin and clicking a marker opened the popup with the customer's name, city, and number of orders:

Customer Map zoomed to Berlin with the popup Customer 14, Berlin, Orders: 4 marked with a red box
The popup of Customer 14.

Customer 14 has four orders in the ORDERS table, as the popup shows. Moving the mouse over a marker showed the tooltip with the customer's name.

Things to Know

  • The background map in this example comes from the internet, with credits for MapTiler and OpenStreetMap; the browser needs access to it.
  • Point Clustering, in the layer's attributes, groups close points into one marker with a count. It needs a Shape for the cluster; saving the page without one failed with Shape Is required!.
  • Each layer has a checkbox in the legend below the map, like Customers here, so users can hide it; a map region can have several layers.

Related Guides

Conclusion

To show customers on a map in Oracle APEX, add latitude and longitude columns, create a Map page with the wizard, and choose Points with Two Numeric Columns.

Name the layer, set its primary key and color, and add a popup with an HTML Expression in the Info Window. Users then see where their customers are and the key facts of each one with a click.

Vinish Kapoor
Vinish Kapoor

An Oracle ACE, author of four books on Oracle APEX, SQL and PL/SQL, and Oracle Forms, and a software developer building Oracle database applications since 2001.

guest

0 Comments
Oldest
Newest Most Voted