Components
51
Accordion Items Article Selection Author Info Basic Carousel Basic Hero Basic Map Pull Out blog Contact Content Accordion Content Carousel Content Image Cta Cta Bar Cta Blocks Cta Collage Event Content Events Grid Example Find Firm Firm Search Firms By Town Gated Content Download Carousel Guides Hero History Hero Homepage Image Content Cta Image List Content Industries Job Content Job Listings Local Firm Carousel Our Firms Carousel pages Partners Partners Slider People Listing Post Carousel Post Feed Pullquote Wrap section Service List Split Content Stats Tax Guides Team Grid Title Logos Two Column Video Video Carousel Video Old

Basic Map

There are no ACF fields assigned to this component.

				
@import "../../resources/scss/util/variables";
@import "../../resources/scss/util/mixins";

.block-basic-map {
	position: relative;
	padding: rem-calc(40px) 0;

	@include bp($md) {
		padding: 0;
	}

	&__content-container {
		display: flex;
		flex-direction: column;
		justify-content: center;
		padding: rem-calc(40px) auto;

		@include bp($md, true) {
			padding-top: 1rem;
		}
	}

	&__map-container {
		height: 100%;
		min-height: 300px;
		position: relative;

		@include bp($md) {
			min-height: 665px;
		}

		// Loading state styles
		&.is-loading {
			position: relative;

			&::before {
				content: '';
				position: absolute;
				top: 50%;
				left: 50%;
				width: 40px;
				height: 40px;
				margin: -20px 0 0 -20px;
				border: 4px solid #f3f3f3;
				border-top: 4px solid #00AEEF; // Using Moore's blue color
				border-radius: 50%;
				z-index: 2;
				animation: spin 1s linear infinite;
			}

			&::after {
				content: '';
				position: absolute;
				top: 0;
				left: 0;
				right: 0;
				bottom: 0;
				background: rgba(255, 255, 255, 0.8);
				z-index: 1;
			}
		}

		// Mapbox popup styling
		.mapboxgl-popup-content {
			font-family: $font-family-primary;
			padding: 1.25rem;
			box-shadow:
				0px 3px 7px 0px #0000001A,
				0px 13px 13px 0px #00000017,
				0px 30px 18px 0px #0000000D,
				0px 54px 21px 0px #00000003,
				0px 84px 23px 0px #00000000;
			text-align: center;
			min-width: 160px;
			font-size: 14px;
			font-weight: 500;
			text-transform: uppercase;
			line-height: 1.2;

		}

		//popup tip
		.mapboxgl-popup-tip {
			margin-top: -1px;
		}

		// Mapbox popup close button styling
		.mapboxgl-popup-close-button {
			font-size: 20px;
			color: #666;
			background: none;
			border: none;
			padding: 5px 8px;
			cursor: pointer;
			line-height: 1;

			&:hover {
				color: #333;
				background-color: #f0f0f0;
				border-radius: 3px;
			}
		}

		// Map controls styling
		.mapboxgl-ctrl-group {
			box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
			border: none;
			border-radius: 4px;

			.mapboxgl-ctrl-zoom-in,
			.mapboxgl-ctrl-zoom-out {
				background-color: white;
				border: none;
				color: #333;
				font-size: 18px;
				width: 30px;
				height: 30px;
				cursor: pointer;

				&:hover {
					background-color: #f0f0f0;
				}
			}
		}
	}

	// Loading animation keyframes
	@keyframes spin {
		0% { transform: rotate(0deg); }
		100% { transform: rotate(360deg); }
	}
}
class BasicMap {
	/**
	 * Create and initialise objects of this class
	 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor
	 * @param {object} block
	 */
	constructor() {
		this.blocks = document.querySelectorAll('.block-basic-map');
		this.init();
	}

	/**
	 * Example function to run class logic
	 * Can access `this.block`
	 */
	init() {
		this.blocks.forEach(block => {
			const lazyLoadMap = (block) => {
				const io = new IntersectionObserver((entries, observer) => {
					entries.forEach(entry => {
						if (entry.isIntersecting) {
							this.initMap(block);
							observer.unobserve(block);
						}
					});
				}, { threshold: [0.7] });

				io.observe(block);
			};

			lazyLoadMap(block);
		});
	}

	initMap(block) {
		if (!window.mapboxgl) {
			console.error('Mapbox GL JS not loaded');
			return;
		}

		const mapContainer = block.querySelector('.block-basic-map__map-container');

		// Create a new token - https://account.mapbox.com/
		mapboxgl.accessToken = 'pk.eyJ1Ijoic3RyYXRlZ2lxIiwiYSI6ImNqc2trb252NzEyZjYzenBvYTRhbmdyNDEifQ.la_5DQo_qJaALM-bp_sc2w';

		let lng = parseFloat(mapContainer.getAttribute('data-lng'));
		let lat = parseFloat(mapContainer.getAttribute('data-lat'));
		let zoom = parseFloat(mapContainer.getAttribute('data-zoom'));

		this.map = new mapboxgl.Map({
			container: mapContainer,
			style: 'mapbox://styles/strategiq/cm6qi73pg010a01r5g5551c8i',
			center: [lng, lat],
			zoom: zoom,
		});

		// Add zoom and rotation controls to the map.
		this.map.addControl(new mapboxgl.NavigationControl());

		// Add marker when map loads
		this.map.on('load', () => {
			// Add marker image
			this.map.loadImage('/wp-content/themes/moore-global/assets/icons/map-pin.png', (error, image) => {
				if (error) throw error;

				this.map.addImage('marker', image);

				// Add marker
				this.map.addSource('marker', {
					type: 'geojson',
					data: {
						type: 'Feature',
						geometry: {
							type: 'Point',
							coordinates: [lng, lat]
						}
					}
				});

				this.map.addLayer({
					id: 'marker-layer',
					type: 'symbol',
					source: 'marker',
					layout: {
						'icon-image': 'marker',
						'icon-size': 1
					}
				});

				// Add click event to marker
				this.map.on('click', 'marker-layer', (e) => {
					const coordinates = e.features[0].geometry.coordinates.slice();
					const address = mapContainer.getAttribute('data-address') || 'Address not available';
					this.showPopup(coordinates, address);
				});

				// Change cursor to pointer when hovering over marker
				this.map.on('mouseenter', 'marker-layer', () => {
					this.map.getCanvas().style.cursor = 'pointer';
				});

				this.map.on('mouseleave', 'marker-layer', () => {
					this.map.getCanvas().style.cursor = '';
				});
			});
		});
	}

	// Method to show popup
	showPopup(coordinates, address) {
		new mapboxgl.Popup()
			.setLngLat(coordinates)
			.setHTML(address)
			.addTo(this.map);
	}
}

// Wait for both DOM and deferred scripts to be ready
document.addEventListener('DOMContentLoaded', () => {
	new BasicMap();
});
{
    "$schema": "https://schemas.wp.org/trunk/block.json",
    "apiVersion": 2,
    "name": "strategiq/basic-map",
    "title": "Basic Map",
    "description": "Example block to be used as a template",
    "category": "strategiq",
    "icon": "strategiq",
    "acf": {
        "mode": "preview",
        "renderTemplate": "block-basic-map.php"
    },
    "supports": {
        "anchor": true,
        "align": false,
        "color": {
            "background": true,
            "text": false,
            "gradients": true
        },
        "spacing": {
            "padding": [
                "top",
                "bottom"
            ],
            "margin": [
                "top",
                "bottom"
            ]
        }
    },
    "example": {
        "attributes": {
            "mode": "preview",
            "data": {
                "heading_type": "h2",
                "heading_text": "Example - Basic Map",
                "content": "This is some example content to represent what the content will look like"
            }
        }
    },
    "style": ["file:../../assets/css/basic-map/block-basic-map.css", "mapbox-styles"],
    "viewScript": ["mapbox-scripts", "basic-map"]
}
This component is not currently used on any pages.
There are no readme files with this component.