Introduction
The purpose of this guide is to cover the most common uses of the KmlLayer and provide corresponding migration paths to alternative implementations. This information is intended for developers who need to transition from using KmlLayer due to its scheduled deprecation. The last version which supports KmlLayer is 3.65, to be decommissioned in May 2027.
Your migration path depends on how you are using the KmlLayer:
- KML file to style boundary/border/area of interest information : Use Data-driven styling (DDS) for boundariesfor administrative areas using Google's boundary data.
- KML file with vector data (Points/Polylines/Boundaries/Polygons)
: Use DDS for datasets, GeoJSON, or 3rd-party librarieslike
deck.glorgeoxml3. - KML file with interactive elements : Implement manual event listeners and custom info windows for feature interaction.
- KML file with imagery : Use GroundOverlaysor 3rd-party parsers for imagery overlays.
- KML File with network Links : Upload each KML as a separate dataset, or merge KMLs. If displaying dynamic data, refresh the dataset using the Datasets API.
- Use KML to display Screen Overlays : Use Custom Controlsto replace fixed UI elements like logos, legends, or navigation aids.
KML file to style boundary/border/area of interest information
For developers using KmlLayer
to display or style administrative
boundaries—such as highlighting a specific country, state, or locality—Google
Maps Platform recommends migrating to Data-driven styling (DDS) for
boundaries.
Migration Recommendation: Data-driven Styling for Boundaries
Data-driven styling for boundaries provides direct access to Google's administrative boundary polygons, allowing you to apply custom styles (fill and stroke) to these regions without needing to host or manage external KML files.
Available FeatureType
Administrative areas are categorized by function and arranged by levels. The following feature types are supported for styling:
-
COUNTRY: The national political entity. -
ADMINISTRATIVE_AREA_LEVEL_1: A first-order civil entity below the country level (e.g., states in the US). -
ADMINISTRATIVE_AREA_LEVEL_2: A second-order civil entity below the country level (e.g., counties in the US). -
LOCALITY: An incorporated city or town. -
POSTAL_CODE: Postal codes as used for mail. -
SCHOOL_DISTRICT: Unified, elementary, or secondary school districts.
See boundary coverage for regions where these feature types are available.
How to Highlight an Area
To style a specific region, you must target it by its Place ID.
- Setup: You must use a Map IDconfigured for JavaScript Vectormap type and enable the Feature layer available in the Google Cloud Console.
- Implementation: use the Style a boundary polygon sample code.
Restricting Panning to an Area
To prevent users from navigating outside the bounding box of your highlighted
area, you can use the restriction
option within the MapOptions
.
The restriction
object defines a latLngBounds
that limits the map's viewable
area. See the documentation
for more details on how the restriction works.
// Restrict panning to a specific bounding box
restriction
:
{
latLngBounds
:
{
north
:
47.8
,
south
:
45.8
,
east
:
10.5
,
west
:
5.9
,
},
strictBounds
:
true
,
},
Summary Migration Implementation
Here is a complete example of how to use Data-driven styling for boundaries and a region restriction to focus the map around a specific area.
const
myTargetRegion
=
"ChIJYW1Zb-9kjEcRFXvLDxG1Vlw"
;
// Place ID for Switzerland
function
initMap
()
{
const
map
=
new
google
.
maps
.
Map
(
document
.
getElementById
(
"map"
),
{
center
:
{
lat
:
46.8
,
lng
:
8.2
},
zoom
:
9
,
mapId
:
"YOUR_MAP_ID"
,
// Required for DDS
// Restrict panning to a specific bounding box
restriction
:
{
// Bounding box for Switzerland
latLngBounds
:
{
north
:
47.8
,
south
:
45.8
,
east
:
10.5
,
west
:
5.9
,
},
strictBounds
:
true
,
},
});
// Access the Country layer and style a specific region by Place ID
const
countryLayer
=
map
.
getFeatureLayer
(
"COUNTRY"
);
countryLayer
.
style
=
(
options
)
=
>
{
if
(
options
.
feature
.
placeId
===
myTargetRegion
)
{
return
{
fillColor
:
"#FF0000"
,
fillOpacity
:
0.5
,
strokeColor
:
"#FF0000"
,
strokeWeight
:
2
,
};
}
else
{
// Style everything else whited out, to make the area of interest pop out more.
return
{
fillColor
:
'#ffffff'
,
fillOpacity
:
0.8
,
};
}
};
}
KML file with vector data (Points/Polylines/Boundaries/Polygons)
Migration Recommendation: Data-driven Styling for Datasets
Google recommends the below path for displaying publicly available geographic data while gaining more control over styling and performance.
Data-driven styling for datasets lets you upload your own geospatial data (KML, GeoJSON, or CSV), apply custom styling based on data attributes, and display features on vector maps.
1. Setup and Upload
Unlike KmlLayer
, which fetches a URL at runtime, DDS requires you to host the
data as a dataset in the Google Cloud Console.
- Create a Map ID: Use a Map ID configured for the Vector maptype.
- Upload the Dataset: Upload your KML file to the Google Cloud Console to generate a unique Dataset ID. Read the full documentation on how to manage Maps Datasets for more details.
- Display the Dataset:Once you have created a Dataset ID, you need to associate the Dataset with a Maps Style and a Map ID. You will then use the Dataset ID to actually display the data on the map. Read the full documentation on how to Add a dataset to a map for all the details.
- Notethe KML requirements for Datasets, if you decide to import your data from the KML format.
2. Setting the Viewport to the Data
KmlLayer
automatically pans and zooms to the data location by default. With
DDS for datasets, this behavior is not automatic and must be implemented
manually.
- Hardcoded Restrictions: If the data area is static, use the
restrictionoption inMapOptionsto lock the viewport to specific bounds. - Dynamic Zooming: To dynamically set the viewport, you can use
map.fitBounds()with the bounding box of your dataset.
3. Styling from Feature Attributes
KML files often contain style information (like colors) that DDS does not automatically apply. You must create a client-side style function that reads attributes from the dataset features to apply colors and opacity. Consult the developer documentation on how to style your data for the full details.
Example: Styling Function using Attributes
The following example demonstrates how to create a style function that reads background_color
and opacity
attributes directly from the uploaded dataset:
/**
* Migration example: Styling features from dataset attributes.
*/
function
styleDDSLayer
(
map
,
datasetId
)
{
const
datasetLayer
=
map
.
getDatasetFeatureLayer
(
datasetId
);
// Set the style function
datasetLayer
.
style
=
(
params
)
=
>
{
// Access attributes defined in your KML/Dataset
const
featureAttributes
=
params
.
feature
.
datasetAttributes
;
// Read style values from attributes, with fallback defaults
const
fillColor
=
featureAttributes
[
'background_color'
]
||
'#4285F4'
;
const
fillOpacity
=
parseFloat
(
featureAttributes
[
'opacity'
])
||
0.5
;
const
strokeColor
=
featureAttributes
[
'border_color'
]
||
'#34A853'
;
return
{
fillColor
:
fillColor
,
fillOpacity
:
fillOpacity
,
strokeColor
:
strokeColor
,
strokeWeight
:
2
,
};
};
}
For further details on implementing interactions and styling, refer to the Data-driven styling for datasets overview and Datasets API for dynamic data.
Migration Recommendation: Client-Side Rendering with GeoJSON
For developers migrating from KmlLayer
to client-side rendering with GeoJSON,
Google Maps Platform recommends a migration path that involves converting your
data format and using the Data layer
to render and style features directly in the browser.
Client-side rendering using the Data layer provides a highly flexible way to
display geographic data. Unlike KmlLayer
,
which is rendered on Google's
servers, the Data layer lets you interact with features as standard
JavaScript objects. Note, however, that for large datasets you might prefer
server-side processing and rendering of your data, such as with Data-driven
Styling for Datasets.
1. Convert KML to GeoJSON
The first step is to convert your KML files into GeoJSON. This can be done using several popular open-source tools:
- ogr2ogr : Part of the GDAL suite, this powerful command-line utility can convert between many vector formats.
ogr2ogr
-f
GeoJSON
output.json
input.kml
- togeojson : A tiny, well-tested tool designed specifically for converting KML and GPX to GeoJSON.
togeojson
input.kml >
output.json
2. Setting the Viewport to the Data
While KmlLayer
automatically pans and zooms to the data location, the Data
layer does not. To set the viewport to fit your GeoJSON data, you must manually
calculate the bounding box and call map.fitBounds()
.
3. Styling from Feature Attributes
In the Data layer, you can define a style
function that reads attributes
(properties) directly from each GeoJSON feature to determine its appearance.
Example: Styling Function and Viewport Adjustment
The following example demonstrates how to load GeoJSON data, calculate its bounds to set the viewport, and style features based on their attributes:
/**
* Migration example: Loading GeoJSON, fitting viewport, and styling from attributes.
*/
function
initMap
()
{
const
map
=
new
google
.
maps
.
Map
(
document
.
getElementById
(
"map"
),
{
zoom
:
4
,
center
:
{
lat
:
-
28
,
lng
:
137
},
});
// Load the GeoJSON data
map
.
data
.
loadGeoJson
(
'path/to/your/data.json'
,
null
,
(
features
)
=
>
{
// Adjust viewport to show all loaded features
const
bounds
=
new
google
.
maps
.
LatLngBounds
();
features
.
forEach
((
feature
)
=
>
{
feature
.
getGeometry
().
forEachLatLng
((
latlng
)
=
>
{
bounds
.
extend
(
latlng
);
});
});
map
.
fitBounds
(
bounds
);
});
// Set the style function to read from GeoJSON properties
map
.
data
.
setStyle
((
feature
)
=
>
{
// Access attributes defined in your GeoJSON properties
const
fillColor
=
feature
.
getProperty
(
'background_color'
)
||
'#4285F4'
;
const
opacity
=
parseFloat
(
feature
.
getProperty
(
'opacity'
))
||
0.5
;
const
strokeColor
=
feature
.
getProperty
(
'border_color'
)
||
'#34A853'
;
return
{
fillColor
:
fillColor
,
fillOpacity
:
opacity
,
strokeColor
:
strokeColor
,
strokeWeight
:
2
,
visible
:
true
};
});
}
For more information on using the Data layer, see the Importing GeoJSON into Maps documentation.
Migration Path: Client-Side Rendering with 3rd party libraries
For developers seeking other alternatives to the KmlLayer
, there are
several community-maintained libraries that render KML data on the Google Maps
Platform JavaScript API.
1. deck.gl
deck.gl
is a high-performance WebGL-powered visualization framework. It can be
used as a near drop-in replacement for KML rendering through its GoogleMapsOverlay
and GeoJsonLayer
.
- Canvas Requirement:To use
deck.gleffectively, you must convert your map to use the Vector map type(which renders to a canvas element) with its WebGL rendering capabilities. - KML Support:Geometry parsing is handled by
@loaders.gl/kml, which converts KML into GeoJSON. Note that some KML features like complex styles, icons, and NetworkLinks may require additional manual implementation. - Documentation: deck.gl Documentation | loaders.gl KML Loader .
- Examples:
- The deckgl-kml-updated sample on the Google Maps GitHub repository demonstrates how to use deck.gl to render KML data that is updated in real-time.
- The deckgl-kml sample demonstrates how to use deck.gl to render KML data.
2. geoxml3
geoxml3
is a KML processor specifically designed for the Google Maps
JavaScript API v3. It parses KML locally in the browser and renders the data as
standard Google Maps API objects like Markers, Polylines, and Polygons.
- Standard Map Support:Unlike WebGL-based solutions,
geoxml3works on standard Google Maps JS API v3 maps without requiring a specific rendering mode. - Caveats:
- Limited KMZ Support:The library does not fully support KMZ
filesnatively; unzipping KMZ archives typically requires integration
with additional 3rd party scripts like
ZipFile.complete.js. - Unsupported Elements:Features such as 3D geometries, complex labels, and certain newer KML elements are not supported.
- Limited KMZ Support:The library does not fully support KMZ
filesnatively; unzipping KMZ archives typically requires integration
with additional 3rd party scripts like
- Documentation: geoxml3 GitHub Repository .
KML file with interactive elements
Migration Recommendation: Data-driven Styling for Datasets
For developers migrating from KmlLayer
to Data-driven styling (DDS) for
datasets, this guide explains how to transition from automatic KML
interactions to custom, high-performance interactions like mouse clicks and
hover.
Initial Setup
Before implementing interactions, ensure you have followed the setup steps from the KML Migration: Vector Dataguide:
- Map ID:Configure a Map ID for the Vector maptype.
- Upload:Upload your KML data to the Google Cloud Console to obtain a Dataset ID.
- Layer Access:Use
map.getDatasetFeatureLayer(datasetId)to access the interactive layer.
1. Handling Interaction Events
In KmlLayer
, feature clicks are handled automatically by the API to pop up an
info window. With DDS for datasets, you must manually register listeners for
mouse events on the dataset layer.
-
click:Triggered when a user clicks on a feature. -
mousemove:Triggered when the cursor moves over a feature, useful for hover effects.
2. Dynamic Styling (Hover Effect)
Because DDS styles are applied globally to the layer, you should maintain a state variable to track which feature is being interacted with and re-apply the style.
let
currentFeatureId
=
null
;
function
initInteraction
(
map
,
datasetId
)
{
const
datasetLayer
=
map
.
getDatasetFeatureLayer
(
datasetId
);
// Apply the style function
datasetLayer
.
style
=
(
params
)
=
>
{
const
isHovered
=
params
.
feature
.
datasetAttributes
[
'id'
]
===
currentFeatureId
;
return
{
strokeColor
:
'green'
,
strokeWeight
:
isHovered
?
4.0
:
2.0
,
// Bold border on hover
fillColor
:
'green'
,
fillOpacity
:
isHovered
?
0.5
:
0.3
,
};
};
// Add interaction listeners
datasetLayer
.
addListener
(
'mousemove'
,
(
event
)
=
>
{
if
(
event
.
features
.
length
>
0
)
{
currentFeatureId
=
event
.
features
[
0
].
datasetAttributes
[
'id'
];
datasetLayer
.
style
=
datasetLayer
.
style
;
// Re-apply style to reflect changes
}
});
// Clear hover state when the mouse leaves the features
map
.
addListener
(
'mousemove'
,
()
=
>
{
if
(
currentFeatureId
!==
null
)
{
currentFeatureId
=
null
;
datasetLayer
.
style
=
datasetLayer
.
style
;
}
});
}
3. Displaying HTML from the description
Attribute
In KML, the <description>
tag often contains HTML for the default info window.
When this data is imported as a dataset, the description
becomes a feature
attribute. To render it, pass the string directly to a standard google.maps.InfoWindow
.
const
infoWindow
=
new
google
.
maps
.
InfoWindow
();
datasetLayer
.
addListener
(
'click'
,
(
event
)
=
>
{
if
(
event
.
features
.
length
>
0
)
{
const
feature
=
event
.
features
[
0
];
// Access the HTML description attribute
const
htmlContent
=
feature
.
datasetAttributes
[
'description'
];
infoWindow
.
setContent
(
htmlContent
);
infoWindow
.
setPosition
(
event
.
latLng
);
infoWindow
.
open
(
map
);
}
});
4. Custom InfoWindow with ExtendedData
If your KML uses <ExtendedData>
to store custom name/value pairs, these are
mapped to datasetAttributes
. You can iterate through these attributes to build
a custom HTML display.
function
createCustomContent
(
feature
)
{
const
attributes
=
feature
.
datasetAttributes
;
const
container
=
document
.
createElement
(
"div"
);
container
.
style
.
padding
=
"10px"
;
container
.
innerHTML
=
"<h3>Feature Details</h3><dl></dl>"
;
const
dl
=
container
.
querySelector
(
"dl"
);
// Iterate through all data attributes imported from KML ExtendedData
for
(
const
key
in
attributes
)
{
const
dt
=
document
.
createElement
(
"dt"
);
dt
.
style
.
fontWeight
=
"bold"
;
dt
.
textContent
=
key
;
const
dd
=
document
.
createElement
(
"dd"
);
dd
.
textContent
=
attributes
[
key
];
dl
.
appendChild
(
dt
);
dl
.
appendChild
(
dd
);
}
return
container
;
}
datasetLayer
.
addListener
(
'click'
,
(
event
)
=
>
{
if
(
event
.
features
.
length
>
0
)
{
const
content
=
createCustomContent
(
event
.
features
[
0
]);
infoWindow
.
setContent
(
content
);
infoWindow
.
setPosition
(
event
.
latLng
);
infoWindow
.
open
(
map
);
}
});
For more advanced visualization techniques, see the developer documentation on how to style data features .
Migration Recommendation: Client-Side Rendering with GeoJSON
For developers migrating from KmlLayer
to client-side rendering with GeoJSON
and the Data layer, this guide explains how to transition from automatic KML
interactions to custom, event-driven interactions and dynamic styling.
Initial Setup
Before implementing interactions, you must convert your KML data to GeoJSON and
load it into the Data layer. Refer to the Migration Recommendation:
Client-Side Rendering with GeoJSONguide for details on using tools like ogr2ogr
or togeojson
and initializing the map with map.data.loadGeoJson()
.
1. Automatic versus Manual Interactions
A key difference between these layers is how they handle user input:
-
KmlLayer: Automatically handles feature clicks and displays anInfoWindowcontaining the KMLanddata. - Data Layer: Does not display
InfoWindowobjects automatically. You must manually add event listeners to capture user interactions and write code to display data.
2. Handling Interaction Events
To make GeoJSON features interactive, use the addListener()
method on the map.data
object. Common events include:
-
click: Used to trigger info windows or selection logic. -
mouseover/mouseout: Used for hover effects and highlighting.
3. Displaying HTML Descriptions in an InfoWindow
When KML is converted to GeoJSON, the <description>
tag (which often contains
HTML) is typically mapped to a property named description
. You can use feature.getProperty('description')
to retrieve this string and render it
inside a standard google.maps.InfoWindow
.
const
infoWindow
=
new
google
.
maps
.
InfoWindow
();
// Handle clicks to show the HTML description
map
.
data
.
addListener
(
'click'
,
(
event
)
=
>
{
// Access the 'description' property from the GeoJSON feature
const
htmlContent
=
event
.
feature
.
getProperty
(
'description'
);
if
(
htmlContent
)
{
infoWindow
.
setContent
(
htmlContent
);
infoWindow
.
setPosition
(
event
.
latLng
);
infoWindow
.
open
(
map
);
}
});
4. Custom InfoWindows and ExtendedData
If your original KML utilized <ExtendedData>
, these name-value pairs are
converted into GeoJSON properties. Because the Data layer doesn't have a default
UI for these, you must implement a custom InfoWindow to iterate through and
display them.
You can access these attributes using event.feature.getProperty('attribute_name')
and construct a custom HTML string
or DOM element to pass to the infoWindow.setContent()
method.
5. Dynamic Styling (Hover Effects)
The Data layer lets you update feature styles programmatically in response
to events. Use overrideStyle()
to temporarily change a feature's appearance
(e.g., on hover) and revertStyle()
to return to the global style.
// Set a base style for all features
map
.
data
.
setStyle
({
fillColor
:
'blue'
,
strokeWeight
:
1
});
// Highlight feature on mouseover
map
.
data
.
addListener
(
'mouseover'
,
(
event
)
=
>
{
map
.
data
.
revertStyle
();
// Clear previous highlights
map
.
data
.
overrideStyle
(
event
.
feature
,
{
strokeWeight
:
8
});
});
// Revert style on mouseout
map
.
data
.
addListener
(
'mouseout'
,
(
event
)
=
>
{
map
.
data
.
revertStyle
();
});
For more detailed implementation details, see the documentation on Data Layer: Event Handling and Data Layer: Dynamic Styling .
Migration Path: Client-Side Rendering with 3rd party libraries
For developers migrating from KmlLayer
to third-party solutions, this guide
focuses on handling interactive data such as mouse clicks and dynamic events
using deck.gland geoxml3.
Initial Setup
Before implementing interactions, ensure you have followed the setup steps from the Migration Path: Client-Side Rendering with 3rd party librariesguide. This includes:
- deck.gl: Converting your map to use the Vector map type(canvas requirement).
- geoxml3: Serving the library scripts from your own host and managing Cross-Origin Resource Sharing (CORS).
1. Interactive Data with deck.gl
deck.gl
supports KML as a direct input format and automatically handles
feature interactions like clicks based on the data provided in the KML file.
- KMLLoader Handling: Using the
@loaders.gl/kmlmodule, geometry and properties are parsed into a format thatdeck.gluses to trigger interaction events natively. - Feature Clicks: When a feature is clicked,
deck.glcan capture the event and display associated metadata (like<name>or<description>). - Example: The deckgl-kml-updated sample demonstrates real-time KML rendering where hovering over earthquake markers displays detailed event information.
2. Interactive Data with geoxml3
geoxml3
parses the KML locally in the browser, extracts style information, and
generates standard Google Maps API objects that retain their interactivity.
- Native Style Extraction: The library grabs
<Style>and<StyleMap>elements from the KML to apply them to the generated Markers, Polylines, and Polygons. - Click Handlers: By default,
geoxml3provides click handlers for these objects. You can also define custom callback functions (createMarker,createOverlay) during parser instantiation to implement your own selection logic or sidebar updates. - Example: This example demonstrates how to use geoxml3 to render KML, with customization like circle markers with interaction, such as clicking on the markers to display earthquake information.
- Usage Pattern:
var
myParser
=
new
geoXML3
.
parser
({
map
:
map
,
processStyles
:
true
,
// Automatically handle KML styles
afterParse
:
function
(
doc
)
{
// Code to run after the KML is fully parsed
}
});
myParser
.
parse
(
'interactive_data.kml'
);
KML file with imagery
For developers using KmlLayer
to display imagery—such as maps with
satellite-derived data, weather patterns, or historical blueprints—this guide
outlines the migration paths to GroundOverlaysor 3rd party parsers.
Migration Recommendation: Maps JavaScript API GroundOverlay
The recommended path for migrating imagery is to use the google.maps.GroundOverlay
class. This lets you place an image on the map
at specific geographic coordinates directly in your code.
1. Implementation
Instead of relying on a KML file to define the bounds, you specify the image URL
and a LatLngBounds
object representing the rectangle on the map.
- Documentation: Ground Overlays Guide .
- Image Preparation: If your image is georeferenced but not in the correct
projection (EPSG:4326), you can use the open-source tool
gdalwarpto warp the image for use with the Maps JS API.
gdalwarp
-t_srs
EPSG:4326
image.jp2
image.jpg
Migration Path: Using 3rd Party Libraries
If your workflow requires you to keep your data in KML format, third-party
libraries like geoxml3
or deck.gl
can be used to render imagery overlays.
Disclaimer:These third-party solutions are not supported by Google. However, they have been tested and should work for most use cases.
1. geoxml3
geoxml3
is a good option for parsing simple GroundOverlay
elements locally
in the browser and converting them into Google Maps API objects.
Example Usage:
const
geoXmlParser
=
new
geoXML3
.
parser
({
map
:
map
,
afterParse
:
function
(
doc
)
{
console
.
log
(
"Parsing complete. Number of documents: "
+
doc
.
length
);
const
bounds
=
doc
[
0
].
gbounds
;
if
(
bounds
&&
!
bounds
.
isEmpty
())
{
map
.
fitBounds
(
bounds
);
}
},
createOverlay
:
function
(
groundOverlayData
)
{
// Extract bounds and URL from parsed KML data
const
imageUrl
=
groundOverlayData
.
icon
.
href
;
const
imageBounds
=
{
north
:
parseFloat
(
groundOverlayData
.
latLonBox
.
north
),
south
:
parseFloat
(
groundOverlayData
.
latLonBox
.
south
),
east
:
parseFloat
(
groundOverlayData
.
latLonBox
.
east
),
west
:
parseFloat
(
groundOverlayData
.
latLonBox
.
west
)
};
// Create the Google Maps GroundOverlay
const
nativeOverlay
=
new
google
.
maps
.
GroundOverlay
(
imageUrl
,
imageBounds
);
nativeOverlay
.
setMap
(
map
);
}
});
geoXmlParser
.
parse
(
'your_file.kml'
);
2. deck.gl
While deck.gl
's standard GeoJsonLayer
handles vector data, it can also
support GroundOverlays
through a manual implementation using the BitmapLayer
.
This approach involves leveraging KMLLoader
to parse the file and then
explicitly defining a BitmapLayer
with the image URL and coordinates extracted
from the KML data.
- Requirement:Using
deck.glrequires a Vector maptype. - Documentation: deck.gl Bitmap Layer
Advanced Case: Tile Pyramids using gdal2tiles
For complex KML files containing imagery tile pyramids, migration is more difficult and requires extracting the imagery data.
- Tool:
gdal2tilescan extract data from a KMZ pyramid and produce standard Maps JavaScript API code to display the tiles. Note that the end result may require manual modification to be incorporated into an existing map.
gdal2tiles
-z
10
-
-n
-u
https://yourhost.com/tiles/
-w
google
input.kmz
KML File with Network Links
Handling KML files with network links requires a shift from the automatic,
cloud-side fetching of KmlLayer
to more explicit data management strategies.
Supported Solution: Data-driven Styling (DDS) for Datasets
Because Google Maps Platform datasets don't natively parse <NetworkLink>
elements, you must choose a migration strategy based on your data structure:
- Strategy A: Distinct Datasets (Best for User-Controlled Layers)Upload
each KML file that was previously a network link as its own individual
dataset in the Google Cloud Console. You can then use JavaScript to
dynamically load and display these layers when needed by calling
map.getDatasetFeatureLayer(datasetId)and adjusting its visibility or style. - Strategy B: Flattened KML File (Best for High-Performance Display)Combine all features from your various network-linked files into a single, comprehensive KML file before uploading it as a dataset. You can then use dynamic stylingbased on feature attributes to filter and display specific data subsets on the fly.
Updating Dynamic Data:To mimic the "auto-refresh" behavior of network links, use the Datasets API to programmatically upload a new version of your dataset whenever the source data changes.
Open-Source Solutions: deck.gl and geoxml3
Neither deck.gl
nor geoxml3
provide robust support for parsing and
automatically fetching KML <NetworkLink>
elements.
deck.gl
deck.gl
utilizes the KMLLoader
(built on togeojson
), which explicitly does not support NetworkLinks.
- Why it is not a good solution:The parser is designed to be a
synchronous, "fuss-free" converter that avoids making its own network
requests to ensure reliability and simplicity. If your application relies on
KML files that point to multiple other URLs,
deck.glwon't automatically resolve them.
geoxml3
While geoxml3
was developed to parse KML for the Maps JS API, its support for
network links is experimental and unmaintained.
- Why it is not a good solution:The functionality exists only in a specific "network_link" branch that is old and not well-tested. Using this for production data migration is discouraged, as it may fail to handle complex link structures or modern security requirements like CORS.
Summary Recommendation
For a reliable migration, developers should avoid third-party parsers for files with network links and instead rebuild the data-fetching logic using the Datasets API. This ensures your data is managed securely within the Google Maps Platform infrastructure rather than relying on unmaintained client-side parsers.
Use KML to display Screen Overlays
For developers migrating from KmlLayer
to modern alternatives like Data-driven
styling (DDS), it is important to note that Screen Overlays are not supported
in Datasets. To achieve the same effect of displaying fixed images, logos, or
legends on top of the map, you must create Custom Controls
using the Maps JavaScript API.
1. What to Look for in Your KML File
To build an equivalent Custom Control, examine the <ScreenOverlay>
element in
your KML file for the following key attributes:
-
<Icon><href>: The URL of the image you want to display. -
<screenXY>: This defines where the overlay is positioned on the screen.-
x=0, y=1(fractions) corresponds to the Top Left. -
x=1, y=1corresponds to the Top Right. -
x=0, y=0corresponds to the Bottom Left. -
x=1, y=0corresponds to the Bottom Right.
-
-
<size>: Defines the width and height of the overlay. -
<rotation>: Indicates if the image should be rotated.
2. Implementation: Creating a Custom Control
A Custom Control is essentially a standard HTML element (like a <div>
or <img>
) that you "push" into one of the map's predefined positions.
Mapping KML Positions to ControlPosition
The Maps JavaScript API uses the ControlPosition
enum to anchor controls. Use
the table below to map your KML <screenXY>
to the appropriate JS API constant:
KML Position ( screenXY
) |
JS API ControlPosition
|
Top Left ( x:0, y:1
) |
TOP_LEFT
(Legacy) or BLOCK_START_INLINE_START
(Logical) |
Top Right ( x:1, y:1
) |
TOP_RIGHT
or BLOCK_START_INLINE_END
|
Bottom Left ( x:0, y:0
) |
BOTTOM_LEFT
or BLOCK_END_INLINE_START
|
Bottom Right ( x:1, y:0
) |
BOTTOM_RIGHT
or BLOCK_END_INLINE_END
|
3. Migration Example: Fixed Logo Overlay
The following example mimics a KML ScreenOverlay logo positioned in the Top Rightof the map.
CSS Styling
Use CSS to define the size and appearance of your "overlay".
#logo
-
control
{
padding
:
10
px
;
background
-
color
:
rgba
(
255
,
255
,
255
,
0.8
);
margin
:
10
px
;
border
-
radius
:
2
px
;
box
-
shadow
:
0
1
px
4
px
rgba
(
0
,
0
,
0
,
0.3
);
}
#logo
-
control
img
{
width
:
150
px
;
/* Equivalent to KML <size> */
display
:
block
;
}
JavaScript Implementation
Add the element to the map.controls
array.
function
initMap
()
{
const
map
=
new
google
.
maps
.
Map
(
document
.
getElementById
(
"map"
),
{
zoom
:
12
,
center
:
{
lat
:
41.85
,
lng
:
-
87.65
},
});
// 1. Create the container for the overlay
const
logoControlDiv
=
document
.
createElement
(
"div"
);
logoControlDiv
.
id
=
"logo-control"
;
// 2. Create the image (KML <Icon>)
const
logoImage
=
document
.
createElement
(
"img"
);
logoImage
.
src
=
"https://example.com/logo.png"
;
logoImage
.
alt
=
"Company Logo"
;
logoControlDiv
.
appendChild
(
logoImage
);
// 3. Position the control (KML <screenXY>)
// In this case, we use TOP_RIGHT
map
.
controls
[
google
.
maps
.
ControlPosition
.
TOP_RIGHT
].
push
(
logoControlDiv
);
}

