Interactive Leaflet Map Viewer and Editor for jQuery - Waymark JS
| File Size: | 6.1 MB |
|---|---|
| Views Total: | 0 |
| Last Update: | |
| Publish Date: | |
| Official Website: | Go to website |
| License: | MIT |
Waymark JS is a jQuery mapping plugin that creates Leaflet-based map viewers and editors. It's great for web apps that need to display GeoJSON data or let users edit markers, lines, and shapes and store the resulting map data in a form.
The plugin uses OpenStreetMap as its default basemap. GeoJSON acts as the main data format, and GPX or KML data can enter a Viewer after conversion to GeoJSON.
Features:
- Read-only Viewer and interactive Editor modes.
- GeoJSON data for markers, lines, and shapes.
- Custom Marker, Line, and Shape Types.
- Marker clustering, overlay filtering, image galleries, and elevation profiles.
- Editable map data synchronized to a form field.
- Custom Slippy Map tile layers and basemap attribution.
- Configurable labels and translated map controls.
- Type-specific CSS classes for custom map styling.
- Access to the underlying Leaflet Map object.
- Sanitized popup descriptions and restricted image URL protocols.
How To Use It:
1. Load Waymark JS
Load the Waymark stylesheet, jQuery, and the Waymark JavaScript bundle in your HTML.
<link rel="stylesheet" href="/dist/latest/css/waymark-js.min.css" /> <script src="/path/to/cdn/jquery.min.js"></script> <script src="/dist/latest/js/waymark-js.min.js"></script>
The library uses npm for source development and building:
git clone https://github.com/OpenGIS/waymark-js cd waymark-js npm install npm run dev npm run build npm test
2. Basic Viewer Example
Create an empty map container:
<div id="waymark-map"></div>
Create a Viewer, initialize the map, and load a GeoJSON FeatureCollection:
<div id="waymark-map"></div>
<script>
const viewer = window.Waymark_Map_Factory.viewer();
viewer.init({
map_options: {
map_init_latlng: [40.7128, -74.006],
map_init_zoom: 13
}
});
viewer.load_json({
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: {
title: "Downtown Office",
description: "Customer support and account services."
},
geometry: {
type: "Point",
coordinates: [-74.006, 40.7128]
}
}
]
});
</script>
Coordinate order changes between the configuration and GeoJSON. Mixing these two formats can place a marker in an unexpected location:
map_init_latlng: [latitude, longitude] GeoJSON coordinates: [longitude, latitude]
3. Connect The Editor To A Form
The Editor works well in CMS forms and location-management screens. It writes the current GeoJSON into a configured data container after map edits.
<form id="property-form" method="post" action="/properties/save">
<label for="property-name">Property name</label>
<input id="property-name" name="property_name" type="text" />
<div id="property-map"></div>
<textarea
id="property-map-data"
name="map_data"
hidden
></textarea>
<button type="submit">Save Property</button>
</form>
<script>
const editor = window.Waymark_Map_Factory.editor();
editor.init({
map_options: {
map_div_id: "property-map",
map_init_latlng: [34.0522, -118.2437],
map_init_zoom: 12
},
editor_options: {
data_div_id: "property-map-data",
confirm_delete: 1
}
});
</script>
4. Load Existing GeoJSON Into An Editor
The Editor can restore an existing map directly from its data container. Place a GeoJSON string inside the textarea before initialization.
<div id="project-map"></div>
<textarea id="project-map-data" name="map_data">
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"title": "Main Entrance"
},
"geometry": {
"type": "Point",
"coordinates": [-122.4194, 37.7749]
}
}
]
}
</textarea>
<script>
const editor = window.Waymark_Map_Factory.editor();
editor.init({
map_options: {
map_div_id: "project-map"
},
editor_options: {
data_div_id: "project-map-data"
}
});
</script>
5. Create Filterable Marker Categories
Types assign reusable styles to map overlays. Viewer filters use the same Type Keys.
<div id="service-map"></div>
<script>
const viewer = window.Waymark_Map_Factory.viewer();
viewer.init({
viewer_options: {
show_filter: 1,
show_cluster: 1
},
map_options: {
map_div_id: "service-map",
map_init_latlng: [41.8781, -87.6298],
map_init_zoom: 12,
marker_types: [
{
marker_title: "Library",
marker_shape: "marker",
marker_size: "medium",
marker_colour: "#31572c",
icon_type: "text",
marker_icon: "L",
icon_colour: "#ffffff"
},
{
marker_title: "Community Center",
marker_shape: "circle",
marker_size: "medium",
marker_colour: "#1d3557",
icon_type: "text",
marker_icon: "C",
icon_colour: "#ffffff"
}
]
}
});
viewer.load_json({
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: {
type: "library",
title: "Northside Library"
},
geometry: {
type: "Point",
coordinates: [-87.65, 41.9]
}
},
{
type: "Feature",
properties: {
type: "communitycenter",
title: "Lakeview Community Center"
},
geometry: {
type: "Point",
coordinates: [-87.64, 41.92]
}
}
]
});
</script>
Waymark derives the Type Key from the Type title. It removes non-alphanumeric characters and converts the result to lowercase.
For example:
Library -> library Community Center -> communitycenter Emergency Point -> emergencypoint
The GeoJSON properties.type value must match that generated key.
6. Load GeoJSON From An API
Initialize the Viewer first, then call load_json() after the request returns the FeatureCollection.
<div id="delivery-map"></div>
<script>
const viewer = window.Waymark_Map_Factory.viewer();
viewer.init({
map_options: {
map_div_id: "delivery-map",
map_init_latlng: [39.7392, -104.9903],
map_init_zoom: 11
}
});
fetch("/api/delivery-zones.geojson")
.then(function (response) {
if (!response.ok) {
throw new Error("Map request failed");
}
return response.json();
})
.then(function (geojson) {
if (
geojson.type !== "FeatureCollection" ||
!Array.isArray(geojson.features)
) {
throw new Error("Expected a GeoJSON FeatureCollection");
}
viewer.load_json(geojson);
})
.catch(function (error) {
console.error(error);
});
</script>
7. Load GPX Or KML Into A Viewer
The production JavaScript bundle contains the toGeoJSON parser. Fetch the file, parse its XML, convert the result to GeoJSON, and load the FeatureCollection.
const viewer = window.Waymark_Map_Factory.viewer();
viewer.init({
viewer_options: {
show_elevation: 1,
elevation_units: "metric"
}
});
fetch("/tracks/weekend-hike.gpx")
.then(function (response) {
return response.text();
})
.then(function (gpxText) {
const xml = new DOMParser().parseFromString(
gpxText,
"text/xml"
);
const geojson = toGeoJSON.gpx(xml) || {};
if (geojson.type !== "FeatureCollection") {
return;
}
viewer.load_json(geojson);
});
KML uses the same conversion pattern:
const geojson = toGeoJSON.kml(xml) || {};
Configuration Options:
Waymark accepts four top-level configuration groups:
const config = {
map_options: {},
viewer_options: {},
editor_options: {},
language: {}
};
Map Options
map_div_id(String, default:"waymark-map"): Sets the ID of the map container.map_height(Number | null, default:null): Sets a fixed map height in pixels.map_width(Number | null, default:null): Sets a fixed map width in pixels.map_init_zoom(Number | null, default:null): Sets the initial zoom level.map_init_latlng(Array | null, default:null): Sets the initial map center in[latitude, longitude]order.map_init_basemap(String | null, default:null): Selects the initial basemap by its exact title.map_max_zoom(Number | null, default:null): Sets the maximum zoom level.show_scale(1|0, default:0): Controls the Leaflet scale display.tile_layers(Array): Defines the available basemaps. OpenStreetMap is the default layer.marker_types(Array, default:[]): Defines Marker Types.line_types(Array, default:[]): Defines Line Types.shape_types(Array, default:[]): Defines Shape Types.debug_mode(1|0, default:0): Writes Waymark debug information to the browser console.
Viewer Options
show_gallery(1|0, default:0): Controls the image gallery for visible Markers with image data.show_filter(1|0, default:1): Controls the Type-based overlay filter.show_cluster(1|0, default:1): Controls clustering for nearby Markers.cluster_radius(Number, default:80): Sets the maximum cluster radius in pixels.cluster_threshold(Number, default:14): Stops clustering above this zoom level.show_elevation(1|0, default:0): Controls the elevation profile for Lines with elevation data.elevation_div_id(String, default:"waymark-elevation"): Sets the element that contains the elevation profile.elevation_units("metric"|"imperial", default:"metric"): Selects metric or imperial elevation units.elevation_colour(CSS color, default:"green"): Sets the elevation graph color.elevation_initial(1|0, default:1): Controls initial elevation-profile visibility.sleep_delay_seconds(Number, default:2): Sets the delay before scroll zoom wakes.sleep_do_message(1|0, default:0): Controls the message shown during sleeping scroll zoom.sleep_wake_message(String, default:"Click or Hover to Wake"): Sets the wake message.
Editor Options
confirm_delete(1|0, default:1): Controls the deletion confirmation message.data_div_id(String, default:"waymark-data"): Sets the element that stores the current GeoJSON.
Basemap Options
Each entry inside map_options.tile_layers accepts these properties:
layer_name(String): Sets the basemap name shown in the layer selector.layer_url(String): Sets the Slippy Map tile URL with{z},{x}, and{y}placeholders.layer_attribution(String): Sets the attribution text or HTML.layer_max_zoom(Number): Sets the maximum zoom level for the tile source.
Example:
const config = {
map_options: {
tile_layers: [
{
layer_name: "OpenStreetMap",
layer_url:
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?r=1",
layer_attribution:
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
layer_max_zoom: 18
}
]
}
};
Marker Type Options
Each entry inside map_options.marker_types accepts these properties:
marker_title(String): Names the Marker Type and generates its Type Key.marker_shape("marker"|"circle"|"rectangle"): Selects the marker shape.marker_size("small"|"medium"|"large"): Selects the marker size.marker_colour(CSS color): Sets the marker background color.icon_type("icon"|"text"|"html"): Selects icon-font, text, emoji, or custom HTML content.marker_icon(String): Sets the icon name, text, emoji, or HTML.icon_colour(CSS color): Sets the icon or text color.
Example:
const config = {
map_options: {
marker_types: [
{
marker_title: "Warehouse",
marker_shape: "marker",
marker_size: "large",
marker_colour: "#30475e",
icon_type: "text",
marker_icon: "W",
icon_colour: "#ffffff"
}
]
}
};
Line Type Options
Each entry inside map_options.line_types accepts these properties:
line_title(String): Names the Line Type and generates its Type Key.line_colour(CSS color): Sets the line color.line_weight(Number): Sets line width in pixels.line_opacity(Number from0to1): Sets line opacity.
const config = {
map_options: {
line_types: [
{
line_title: "Delivery Path",
line_colour: "#287271",
line_weight: 4,
line_opacity: 0.8
}
]
}
};
Shape Type Options
Each entry inside map_options.shape_types accepts these properties:
shape_title(String): Names the Shape Type and generates its Type Key.shape_colour(CSS color): Sets the shape color.fill_opacity(Number from0to1): Sets interior opacity.
const config = {
map_options: {
shape_types: [
{
shape_title: "Service Area",
shape_colour: "#2a9d8f",
fill_opacity: 0.3
}
]
}
};
GeoJSON Overlay Properties
Waymark reads several properties from GeoJSON Features to construct overlay content.
Markers, Lines, and Shapes can use:
type: Assigns the Feature to a configured Type Key.title: Sets the overlay title.description: Sets the popup description.image_thumbnail_url: Stores a thumbnail image URL.image_medium_url: Stores a medium image URL.image_large_url: Stores a large image URL.
Lines can also use:
direction: Stores line-direction data used by Waymark's Line controls.
Popup titles render as text. Description HTML passes through an allowlist sanitizer. Image URLs must use http or https.
Localization
Pass translated strings through the top-level language object.
const config = {
language: {
action_zoom_in: "Acercar",
action_zoom_out: "Alejar",
action_delete: "Eliminar",
action_edit: "Editar",
action_search_placeholder: "Buscar..."
}
};
const editor = window.Waymark_Map_Factory.editor();
editor.init(config);
A missing translation falls back to the default English string.
Available language keys include:
const language = {
action_fullscreen_activate: "View Fullscreen",
action_fullscreen_deactivate: "Exit Fullscreen",
action_locate_activate: "Show me where I am",
action_zoom_in: "Zoom in",
action_zoom_out: "Zoom out",
label_total_length: "Total Length: ",
label_max_elevation: "Max. Elevation: ",
label_min_elevation: "Min. Elevation: ",
label_ascent: "Total Ascent: ",
label_descent: "Total Descent: ",
add_line_title: "Draw a Line",
add_photo_title: "Upload an Image",
add_marker_title: "Place a Marker",
add_rectangle_title: "Draw a Rectangle",
add_polygon_title: "Draw a Polygon",
add_circle_title: "Draw a Circle",
upload_file_title:
"Read Lines and Markers from file (GPX/KML/GeoJSON supported, which most apps should Export to)",
action_duplicate: "Duplicate",
action_delete: "Delete",
action_edit: "Edit",
action_edit_done: "Finish editing",
action_upload_image: "Upload Image",
object_title_placeholder: "Title",
object_image_placeholder: "Image URL",
object_description_placeholder: "Description",
object_type_label: "Type",
marker_latlng_label: "Lat,Lng",
action_delete_confirm: "Are you sure you want to delete this",
action_search_placeholder: "Search...",
object_label_marker: "Marker",
object_label_line: "Line",
object_label_shape: "Shape",
object_label_marker_plural: "Markers",
object_label_line_plural: "Lines",
object_label_shape_plural: "Shapes",
error_message_prefix: "Waymark Error",
info_message_prefix: "Waymark Info",
debug_message_prefix: "Waymark Debug",
error_file_type: "This file type is not supported.",
error_file_conversion: "Could not convert this file to GeoJSON.",
error_file_upload: "File upload error.",
error_photo_meta: "Could not retrieve Image metadata.",
info_exif_yes: "Image location metadata (EXIF) detected!",
info_exif_no: "Image location metadata (EXIF) NOT detected.",
error_no_wpmedia: "WordPress Media Library not found",
no_direction: "No Direction",
show_direction: "Show Direction",
reverse_direction: "Reverse Direction",
sleep_wake_message: "Click or Hover to Wake"
};
API Methods:
Factory Methods
// Create a read-only Viewer instance. const viewer = window.Waymark_Map_Factory.viewer(); // Create an editable Editor instance. const editor = window.Waymark_Map_Factory.editor();
Instance Methods
// Initialize a Viewer or Editor.
viewer.init({
map_options: {
map_init_zoom: 12
}
});
// Load a GeoJSON FeatureCollection.
viewer.load_json(featureCollection);
// The same methods work with an Editor instance.
editor.init(editorConfig);
editor.load_json(featureCollection);
Exposed Leaflet Objects
Waymark exposes the underlying Leaflet Map through the instance's map property:
const leafletMap = viewer.map;
The current geographical state lives in map_data, which is a Leaflet GeoJSON layer:
const geojson = editor.map_data.toGeoJSON();
Callback And Leaflet Events:
The global waymark_loaded_callback function runs after a map finishes initialization. It receives the Waymark instance.
function waymark_loaded_callback(instance) {
const container = instance.map.getContainer();
container.classList.add("map-ready");
}
The exposed Leaflet Map supports normal Leaflet events:
const viewer = window.Waymark_Map_Factory.viewer();
viewer.init();
viewer.map.on("popupopen", function (event) {
const layer = event.popup._source;
console.log("Opened feature:", layer.feature);
});
Styling Waymark Maps:
Waymark elements use waymark- CSS classes. Type Keys appear in generated class names, which makes category-specific styling straightforward.
A Marker Type named Warehouse generates a class such as:
<div class="waymark-marker waymark-marker-warehouse"> ... </div>
Target that Type from your own stylesheet:
.waymark-marker.waymark-marker-warehouse .waymark-marker-background {
background-color: #1d3557 !important;
}
.waymark-marker.waymark-marker-warehouse .waymark-marker-icon {
color: #ffffff !important;
}
Alternatives And Related Resources:
-
am_map.js: Create a smaller jQuery and Leaflet map with multiple marker layers and popups.
-
Leaflet Location Picker: Turn a text input into a Leaflet coordinate picker when a form needs one selected location.
-
jQuery Geo: Build editable geographic maps through a larger jQuery mapping API.
-
shadcn/ui Leaflet Map: Use Leaflet inside React and shadcn/ui projects with markers, popups, drawing controls, and TypeScript-friendly components.
This awesome jQuery plugin is developed by OpenGIS. For more Advanced Usages, please check the demo page or visit the official website.
- Prev: Drag and Drop Nested Tree for Bootstrap - BsNestedSortable
- Next: None











