I am trying to use mapbox-gl with magento2 which uses requireJS. Mapbox-js seems to load but I have got a js error. I don't know if I missed requirejs config or if the error is due to my js code or if it's a bug ?
If someone can help me, thanks you.
mapbox-gl-js version: v1.0.0, v1.2.0 and v1.3.0
browser: Chrome
Steps to Trigger Behavior
1.Try to use mapbox into magento2 with requireJs
2.
3.
Link to Demonstration
No demonstration available sorry.
Expected Behavior
No error
Actual Behavior
Error in broswer console :
mapbox-gl-3.js:635 Uncaught TypeError: self.XMLHttpRequest is not a constructor at mapbox-gl-3.js:635 at dt (mapbox-gl-3.js:654) at Object.mt [as getArrayBuffer] (mapbox-gl-3.js:656) at Function.v.loadGlyphRange (mapbox-gl-3.js:11511) at mapbox-gl-3.js:11474 at mapbox-gl-3.js:9863 at Array.forEach () at Object.t.asyncAll (mapbox-gl-3.js:9862) at v.getGlyphs (mapbox-gl-3.js:11466) at i.getGlyphs (mapbox-gl-3.js:14227) (anonymous) # mapbox-gl-3.js:635 dt # mapbox-gl-3.js:654 mt # mapbox-gl-3.js:656 v.loadGlyphRange # mapbox-gl-3.js:11511 (anonymous) # mapbox-gl-3.js:11474 (anonymous) # mapbox-gl-3.js:9863 t.asyncAll # mapbox-gl-3.js:9862 v.getGlyphs # mapbox-gl-3.js:11466 i.getGlyphs # mapbox-gl-3.js:14227 du.receive # mapbox-gl-3.js:8739
At this moment, this is undefined, I guess it shouldn't but i don 't know how to fix it.
requirejs-config:
var config = { deps: [ [...] ], map: { '*': { [...] mapboxgl: "js/mapbox-gl-3", MapboxGeocoder: "js/mapbox-gl-geocoder.min", turf: "js/turf.min" } }, paths: { [...] }, config: { mixins: { [...] } }, shim : { 'mapbox-gl': { exports: 'mapbox-gl' }, 'leaflet-mapbox-gl': { deps: ['leaflet','mapbox-gl'] } } };
script JS :
`
require(['mapboxgl', 'MapboxGeocoder', 'turf'], function (mapboxgl, MapboxGeocoder, turf) {
// This will let you use the .remove() function later on
if (!('remove' in Element.prototype)) {
Element.prototype.remove = function () {
if (this.parentNode) {
this.parentNode.removeChild(this);
}
};
}
console.log('vahir2');
mapboxgl.accessToken = 'my_token_here';
// This adds the map
var map = new mapboxgl.Map({
// container id specified in the HTML
container: 'map',
// style URL
style: 'mapbox://styles/mapbox/streets-v9?optimize=true',
// initial position in [long, lat] format
center: [6.8541548, 46.4564862],
// initial zoom
zoom: 5,
scrollZoom: true
});
console.log('vahir3');
map.addControl(new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true,
showUserLocation: true
}));
map.addControl(new mapboxgl.NavigationControl());
//geocoder
var geocoder = new MapboxGeocoder({
accessToken: mapboxgl.accessToken, // Set the access token
mapboxgl: mapboxgl, // Set the mapbox-gl instance
marker: false, // Do not use the default marker style
bbox: [-5.7616150379, 41.9409963458, 19.6387755871, 55.208571099]
});
map.addControl(geocoder, 'top-left');
// This adds the data to the map
map.on('load', function (e) {
map.addSource('single-point', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: [] // Notice that initially there are no features
}
});
map.addLayer({
id: 'point',
source: 'single-point',
type: 'circle',
paint: {
'circle-radius': 10,
'circle-color': '#007cbf',
'circle-stroke-width': 3,
'circle-stroke-color': '#fff'
}
});
geocoder.on('result', function (ev) {
var searchResult = ev.result.geometry;
map.getSource('single-point').setData(searchResult);
var options = {units: 'kilometers'};
stores.features.forEach(function (store) {
Object.defineProperty(store.properties, 'distance', {
value: turf.distance(searchResult, store.geometry, options),
writable: true,
enumerable: true,
configurable: true
});
});
stores.features.sort(function (a, b) {
if (a.properties.distance > b.properties.distance) {
return 1;
}
if (a.properties.distance < b.properties.distance) {
return -1;
}
// a must be equal to b
return 0;
});
var listings = document.getElementById('listings');
while (listings.firstChild) {
listings.removeChild(listings.firstChild);
}
buildLocationList(stores);
function sortLonLat(storeIdentifier) {
var lats = [stores.features[storeIdentifier].geometry.coordinates[1], searchResult.coordinates[1]];
var lons = [stores.features[storeIdentifier].geometry.coordinates[0], searchResult.coordinates[0]];
var sortedLons = lons.sort(function (a, b) {
if (a > b) {
return 1;
}
if (a.distance < b.distance) {
return -1;
}
return 0;
});
var sortedLats = lats.sort(function (a, b) {
if (a > b) {
return 1;
}
if (a.distance < b.distance) {
return -1;
}
return 0;
});
map.fitBounds([
[sortedLons[0], sortedLats[0]],
[sortedLons[1], sortedLats[1]]
], {
padding: 100
});
}
sortLonLat(0);
createPopUp(stores.features[0]);
});
// This is where your '.addLayer()' used to be, instead add only the source without styling a layer
map.addSource("places", {
"type": "geojson",
"data": stores,
tolerance: 3
});
// Initialize the list
buildLocationList(stores);
});
// This is where your interactions with the symbol layer used to be
// Now you have interactions with DOM markers instead
stores.features.forEach(function (marker, i) {
// Create an img element for the marker
var el = document.createElement('div');
el.id = "marker-" + i;
el.className = 'marker';
// Add markers to the map at all points
new mapboxgl.Marker(el, {
offset: [0, -23]
})
.setLngLat(marker.geometry.coordinates)
.addTo(map);
el.addEventListener('click', function (e) {
// 1. Fly to the point
flyToStore(marker);
// 2. Close all other popups and display popup for clicked store
createPopUp(marker);
// 3. Highlight listing in sidebar (and remove highlight for all other listings)
var activeItem = document.getElementsByClassName('active');
e.stopPropagation();
if (activeItem[0]) {
activeItem[0].classList.remove('active');
}
var listing = document.getElementById('listing-' + i);
listing.classList.add('active');
});
});
function flyToStore(currentFeature) {
map.flyTo({
center: currentFeature.geometry.coordinates,
zoom: 15
});
}
function createPopUp(currentFeature) {
var popUps = document.getElementsByClassName('mapboxgl-popup');
if (popUps[0]) popUps[0].remove();
var popup = new mapboxgl.Popup({
closeOnClick: false
})
.setLngLat(currentFeature.geometry.coordinates)
.setHTML('<h3>' + currentFeature.properties.name + '</h3>' +
'<h4>' + currentFeature.properties.desc + '</h4><img style="padding: 0% 0% 5% 6%;" src="/media/wysiwyg/store-locator/' + currentFeature.properties.image + '" />')
.addTo(map);
}
function buildLocationList(data) {
for (i = 0; i < data.features.length; i++) {
var currentFeature = data.features[i];
var prop = currentFeature.properties;
var listings = document.getElementById('listings');
var listing = listings.appendChild(document.createElement('div'));
listing.className = 'item';
listing.id = "listing-" + i;
if (prop.capsules == 1) {
var icon = listing.appendChild(document.createElement('img'));
icon.src = '/media/wysiwyg/store-locator/icon_capsule.png';
icon.style = 'float: right; height:18px;';
}
if (prop.machines == 1) {
var icon = listing.appendChild(document.createElement('img'));
icon.src = '/media/wysiwyg/store-locator/icon_machine.png';
icon.style = 'float: right; height:18px;';
}
var link = listing.appendChild(document.createElement('a'));
link.href = '#';
link.className = 'title';
link.dataPosition = i;
link.innerHTML = prop.name;
var details = listing.appendChild(document.createElement('div'));
details.innerHTML = prop.desc;
if (prop.distance) {
var roundedDistance = Math.round(prop.distance * 100) / 100;
details.innerHTML += '<p><strong>Distance : ' + roundedDistance + ' km</strong></p>';
}
link.addEventListener('click', function (e) {
// Update the currentFeature to the store associated with the clicked link
var clickedListing = data.features[this.dataPosition];
// 1. Fly to the point
flyToStore(clickedListing);
// 2. Close all other popups and display popup for clicked store
createPopUp(clickedListing);
// 3. Highlight listing in sidebar (and remove highlight for all other listings)
var activeItem = document.getElementsByClassName('active');
if (activeItem[0]) {
activeItem[0].classList.remove('active');
}
this.parentNode.classList.add('active');
});
}
}
});
`
Finally I found out that a tiers vendor overwritten "self".
Related
I think I'm doing something wrong in the variables or syntax... i don't know, help me to correct my code. (I'm using Leaflet for the map show)
Desired Behavior
The user should be able to see the BBOX entering the coordinates into the URL, for example:
.com/#013.0,052.0,013.5,052.5
I only care that the BBOX is shown, I don't care that the URL coordinates change when zooming or moving around the map.
My HTML
<!DOCTYPE html>
<html>
<header>
<link rel="stylesheet" href="style.css" />
<link
rel="stylesheet"
href="https://unpkg.com/leaflet#1.9.3/dist/leaflet.css"
integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI="
crossorigin=""
/>
<script
src="https://unpkg.com/leaflet#1.9.3/dist/leaflet.js"
integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM="
crossorigin=""
></script>
</header>
<body>
<div id="map"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script src="https://unpkg.com/leaflet#1.0.1/dist/leaflet.js"></script>
<script src="leaflet-hash.js"></script>
<script>
var map = L.map("map").setView([42, 12], 4);
// var hash = new L.hash(map);
var urlhash = window.location.hash.substring(1).split("/");
var boundingBox = "";
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
maxZoom: 22,
minZoom: 1,
continuousWorld: false,
noWrap: false,
attribution:
'Data by OpenStreetMap, under ODbL.',
detectRetina: false,
}).addTo(map);
var bboxField = L.control({
position: "bottomleft",
});
bboxField.onAdd = function (map) {
//create div container for control
var div = L.DomUtil.create("div", "myButtonBar");
//prevent mouse events from propagating through to the map
L.DomEvent.disableClickPropagation(div);
//create custom radio buttons
div.innerHTML =
'BBOX (Left (LON) ,Bottom (LAT), Right (LON), Top (LAT), comma separated, with or without decimal point):<br><input type="text" id="bbox_field"/><button id="setDimensions">Display BBOX</button><button id="remove">Remove</button>';
return div;
};
bboxField.addTo(map);
$(".myButtonBar").css("font-weight", "bold");
if (urlhash[0] !== "") {
$("#bbox_field").val(urlhash[0]);
draw_bbox(urlhash[0]);
}
function draw_bbox(box) {
var myarray = box.split(",");
var bounds = [
[myarray[1], myarray[0]],
[myarray[3], myarray[2]],
];
boundingBox = L.rectangle(bounds, { color: "#ff7800", weight: 1 });
map.removeLayer(boundingBox);
boundingBox.addTo(map);
map.fitBounds(boundingBox.getBounds());
map.setZoom(map.getZoom() - 1);
}
$("#setDimensions").click(function () {
draw_bbox($("#bbox_field").val());
});
$("#bbox_field").keyup(function (event) {
if (event.keyCode === 13) {
$("#setDimensions").click();
}
});
// console.log(bbox)
$("#remove").click(function () {
map.removeLayer(boundingBox);
});
</script>
</body>
</html>
Leaflet Hash Plugin Code
(function(window) {
var HAS_HASHCHANGE = (function() {
var doc_mode = window.documentMode;
return ('onhashchange' in window) &&
(doc_mode === undefined || doc_mode > 7);
})();
L.hash = function(map) {
this.onHashChange = L.Util.bind(this.onHashChange, this);
if (map) {
this.init(map);
}
};
L.hash.parseHash = function(hash) {
if(hash.indexOf('#') === 0) {
hash = hash.substr(1);
}
var args = hash.split("/");
if (args.length == 3) {
var zoom = parseInt(args[0], 10),
lat = parseFloat(args[1]),
lon = parseFloat(args[2]);
if (isNaN(zoom) || isNaN(lat) || isNaN(lon)) {
return false;
} else {
return {
center: new L.LatLng(lat, lon),
zoom: zoom
};
}
} else {
return false;
}
};
L.hash.formatHash = function(map) {
var center = map.getCenter(),
zoom = map.getZoom(),
precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
return "#" + [zoom,
center.lat.toFixed(precision),
center.lng.toFixed(precision)
].join("/");
},
L.hash.prototype = {
map: null,
lastHash: null,
parseHash: L.hash.parseHash,
formatHash: L.hash.formatHash,
init: function(map) {
this.map = map;
// reset the hash
this.lastHash = null;
this.onHashChange();
if (!this.isListening) {
this.startListening();
}
},
removeFrom: function(map) {
if (this.changeTimeout) {
clearTimeout(this.changeTimeout);
}
if (this.isListening) {
this.stopListening();
}
this.map = null;
},
onMapMove: function() {
// bail if we're moving the map (updating from a hash),
// or if the map is not yet loaded
if (this.movingMap || !this.map._loaded) {
return false;
}
var hash = this.formatHash(this.map);
if (this.lastHash != hash) {
location.replace(hash);
this.lastHash = hash;
}
},
movingMap: false,
update: function() {
var hash = location.hash;
if (hash === this.lastHash) {
return;
}
var parsed = this.parseHash(hash);
if (parsed) {
this.movingMap = true;
this.map.setView(parsed.center, parsed.zoom);
this.movingMap = false;
} else {
this.onMapMove(this.map);
}
},
// defer hash change updates every 100ms
changeDefer: 100,
changeTimeout: null,
onHashChange: function() {
// throttle calls to update() so that they only happen every
// `changeDefer` ms
if (!this.changeTimeout) {
var that = this;
this.changeTimeout = setTimeout(function() {
that.update();
that.changeTimeout = null;
}, this.changeDefer);
}
},
isListening: false,
hashChangeInterval: null,
startListening: function() {
this.map.on("moveend", this.onMapMove, this);
if (HAS_HASHCHANGE) {
L.DomEvent.addListener(window, "hashchange", this.onHashChange);
} else {
clearInterval(this.hashChangeInterval);
this.hashChangeInterval = setInterval(this.onHashChange, 50);
}
this.isListening = true;
},
stopListening: function() {
this.map.off("moveend", this.onMapMove, this);
if (HAS_HASHCHANGE) {
L.DomEvent.removeListener(window, "hashchange", this.onHashChange);
} else {
clearInterval(this.hashChangeInterval);
}
this.isListening = false;
}
};
L.hash = function(map) {
return new L.hash(map);
};
L.map.prototype.addHash = function() {
this._hash = L.hash(this);
};
L.map.prototype.removeHash = function() {
this._hash.removeFrom();
};
})(window);
I am customizing the WordPress Geodirectory plugin's Google Maps API functionality to store the user set/selected map type, marker, and zoom level in local storage.
I have the user set map type and zoom level functionality working, but am struggling with implementing the selected map marker.
How would I go about storing and retrieving the selected map marker from local storage and displaying it on the map when the user clicks/taps back in the browser?
My existing custom code is included below:
const zoomChangeListener = google.maps.event.addListener(jQuery.goMap.map, 'zoom_changed', function (event) {
storeUserZoom();
});
loadUserZoom();
function storeUserZoom() {
let zoom = jQuery.goMap.map.getZoom();
localStorage.setItem( 'zoom', zoom);
// console.log('Storing zoom level: ' + zoom);
}
function loadUserZoom() {
let zoom = localStorage.getItem( 'zoom' );
if (localStorage.getItem( 'zoom' )) {
jQuery.goMap.map.setZoom(parseInt(zoom));
// console.log('Local storage zoom level: ' + zoom);
}
}
const mapTypeChangeListener = google.maps.event.addListener(jQuery.goMap.map, 'maptypeid_changed', function (event) {
storeUserMapType();
});
loadUserMapType();
function storeUserMapType() {
let mapType = jQuery.goMap.map.getMapTypeId();
localStorage.setItem( 'maptype', mapType);
// console.log('Map type changed: ' + mapType);
}
function loadUserMapType() {
let mapType = localStorage.getItem( 'maptype' );
if (localStorage.getItem( 'maptype' )) {
jQuery.goMap.map.setMapTypeId(mapType);
// console.log('Loading map type: ' + mapType);
}
}
function storeUserMarker(item, map_canvas) {
let markerId, markerTitle, markerIcon, markerPosition;
markerId = item.id;
markerTitle = item.title;
markerIcon = item.icon = {
url: item.icon,
// scaledSize: new google.maps.Size(resizeW, resizeH),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(0, 0)
};
// markerIcon = item.icon;
// console.log(markerIcon);
markerPosition = item.position;
localStorage.setItem( 'id', markerId );
localStorage.setItem( 'title', markerTitle );
localStorage.setItem( 'icon', JSON.stringify(markerIcon) );
localStorage.setItem( 'position', JSON.stringify(markerPosition));
}
function loadUserMarker(item, map_canvas) {
let markerId = localStorage.getItem( 'id' );
let markerTitle = localStorage.getItem( 'title' );
let markerIcon = JSON.parse(localStorage.getItem( 'icon' ));
let markerPosition = JSON.parse(localStorage.getItem( 'position' ));
if (localStorage.getItem( 'position' )) {
let marker = {
id: markerId,
title: markerTitle,
icon: markerIcon,
position: markerPosition,
visible: true,
clickable: true
};
gd_infowindow.open(jQuery.goMap.map, marker);
}
}
Geodirectory initMap function simplified with my additions marked as custom code
function initMap(map_options, marker) {
/** Custom code begin **/
google.maps.event.addListener(jQuery.goMap.map, 'tilesloaded', function() {
loadUserMarker(marker);
});
/** Custom code end **/
}
Geodirectory create_marker function with my additions marked as custom code
// create the marker and set up the event window
function create_marker(item, map_canvas) {
if (window.gdMaps == 'osm') {
return create_marker_osm(item, map_canvas);
}
var map_options = eval(map_canvas);
jQuery("#" + map_canvas).goMap();
gd_infowindow = (typeof google !== 'undefined' && typeof google.maps !== 'undefined') ? new google.maps.InfoWindow({
maxWidth: 200
}) : null;
if (item.lt && item.ln) {
var marker_id, title, icon, cs;
marker_id = item['m'];
title = geodir_htmlEscape(item['t']);
cs = item['cs'];
icon = item['icon'] ? item['icon'] : geodir_params.default_marker_icon;
iconW = item['w'] ? parseFloat(item['w']) : 0;
iconH = item['h'] ? parseFloat(item['h']) : 0;
iconMW = geodir_params.marker_max_width ? parseFloat(geodir_params.marker_max_width) : 0;
iconMH = geodir_params.marker_max_height ? parseFloat(geodir_params.marker_max_height) : 0;
/* Some svg files has dimensions with different unit */
if (geodir_params.resize_marker && ( iconW < iconMW || iconH < iconMH ) && icon.substr((icon.lastIndexOf('.')+1)).toLowerCase() == 'svg') {
iconW = iconW * 10;
iconH = iconH * 10;
}
if (geodir_params.resize_marker && iconW > 5 && iconH > 5 && ((iconMW > 5 && iconW > iconMW) || (iconMH > 5 && iconH > iconMH))) {
resizeW = iconW;
resizeH = iconH;
resize = false;
if (iconMH > 5 && resizeH > iconMH) {
_resizeH = iconMH;
_resizeW = Math.round(((_resizeH * resizeW) / resizeH) * 10) / 10;
resizeW = _resizeW;
resizeH = _resizeH;
resize = true;
}
if (iconMW > 5 && resizeW > iconMW) {
_resizeW = iconMW;
_resizeH = Math.round(((_resizeW * resizeH) / resizeW) * 10) / 10;
resizeW = _resizeW;
resizeH = _resizeH;
resize = true;
}
if (resize && resizeW > 5 && resizeH > 5) {
icon = {
url: icon,
scaledSize: new google.maps.Size(resizeW, resizeH),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point((Math.round(resizeW / 2)), resizeH)
};
}
}
var latlng = new google.maps.LatLng(item.lt, item.ln);
var marker = jQuery.goMap.createMarker({
id: marker_id,
title: title,
position: latlng,
visible: true,
clickable: true,
icon: icon,
label: cs,
zIndex: (item.zIndex ? item.zIndex : 0),
zIndexOrg: (item.zIndexOrg ? item.zIndexOrg : 0)
});
bounds.extend(latlng);
// Adding a click event to the marker
google.maps.event.addListener(marker, 'spider_click', function() { // 'click' => normal, 'spider_click' => Overlapping Marker Spiderfier
/** Custom code begin **/
storeUserMarker(marker);
/** Custom code end **/
var marker_url = map_options.map_marker_ajax_url;
is_zooming = true;
jQuery("#" + map_canvas).goMap();
var preview_query_str = '';
if (item.post_preview) {
preview_query_str = '&post_preview=' + item.post_preview;
}
marker_url = marker_url + '' + item.m;
post_data = marker_url.indexOf('?') === -1 ? '?' : '&';
post_data += '_wpnonce=' + map_options._wpnonce;
if (map_options.bubble_size) {
post_data += '&small=1';
}
if (map_options.map_marker_url_params) {
post_data += map_options.map_marker_url_params;
}
var loading = '<div id="map_loading"></div>';
gd_infowindow.open(jQuery.goMap.map, marker);
gd_infowindow.setContent(loading);
jQuery.ajax({
type: "GET",
url: marker_url + post_data,
cache: false,
dataType: "json",
error: function(xhr, error) {
alert(error);
},
success: function(response) {
jQuery("#" + map_canvas).goMap();
html = typeof response == 'object' && response.html ? geodir_htmlEscape(response.html) : '';
gd_infowindow.setContent(html);
gd_infowindow.open(jQuery.goMap.map, marker);
setTimeout(function() {
jQuery(document.body).trigger('geodir_map_infowindow_open', [{
map: 'google',
canvas: map_canvas,
content: html
}]);
}, 100);
// give the map 1 second to reposition before allowing it to reload
setTimeout(function() {
is_zooming = false;
}, 1000);
}
});
return;
});
// Overlapping Marker Spiderfier
jQuery.goMap.oms.addMarker(marker);
// Adding a visible_changed event to the marker
google.maps.event.addListener(marker, 'visible_changed', function() {
gd_infowindow.close(jQuery.goMap.map, marker);
});
return true;
} else {
//no lat & long, return no marker
return false;
}
}
The loadUserMarker(); function returns [object Object] in the console when executed.
The functionality can be tested on the staging site. Try clicking on a map marker, visiting the individual page, then return to the map with the browser back button.
Update
I am receiving the following error when trying to load the previously clicked/tapped map marker: Uncaught (in promise) TypeError: b.anchor.get is not a function. I know it relates to anchoring the info window to the map marker, but I am not sure how to correct it.
My storeUserMarker function has been updated to make item.icon into an object that includes the marker URL, origin, and anchor.
How would I go about getting the marker's anchor data so the info window can be displayed?
I'm trying to add markers to leaflet.indoor. I am getting my data from a geoJson file. I keep getting this error "Uncaught TypeError: Cannot read property 'addLayer' of undefined" leaflet-indoor.js:57 . i am relatively new to javascript and programming.
here is my code.
$.getJSON("gateway.json", function(geoJSON) {
var indoorLayer = new L.Indoor(gateway, {
getLevel: function(feature) {
if (feature.properties.length === 0)
return null;
return feature.properties.level;
},
markerForFeature: function(feature) {
var content = feature.properties.name;
var iconCoords = feature.properties.center;
var myIcon = L.divIcon({
className: 'ls-room-marker',
html: content,
iconSize: new L.Point(100, 14),
iconAnchor: new L.Point(50, 7)
});
var marker = L.marker(iconCoords, {
icon: myIcon
});
return marker;
},
onEachFeature: function(feature, layer) {
layer.bindPopup(JSON.stringify(feature.properties, null, 2));
},
style: function(feature) {
var fill = 'white';
if (feature.properties.buildingpart === 'base') {
fill = 'silver';
} else if (feature.properties.buildingpart === 'hallway') {
fill = 'cornsilk';
}
return {
fillColor: fill,
weight: 1,
color: '#666',
fillOpacity: 1
};
}
});
indoorLayer.setLevel("0");
indoorLayer.addTo(map);
var levelControl = new L.Control.Level({
level: "0",
levels: indoorLayer.getLevels()
});
// Connect the level control to the indoor layer
levelControl.addEventListener("levelchange", indoorLayer.setLevel, indoorLayer);
levelControl.addTo(map);
});
i edited the part of the code as show below, but i still get no labels.
markerForFeature: function(feature) {
if (feature.properties.category === "general"){
var iconCoords = feature.properties.center;
var content;
if ("name" in feature.properties && "category" in feature.properties) {
content = feature.properties.name + "(" + feature.properties.category + ")";
}
else if
("category" in feature.properties) {
content = feature.properties.category;
} else if ("name" in feature.properties) {
content = feature.properties.name;
} else {
return;
}
//I tried to use
this.map.on('click', this.onMapClick);
//that failed
//I changed to
this.map.on('click', (e)=> {this.onMapClick(e)});
//And that work's, don't ask me why
I am trying to implement a plugin that allows the user to dump relevant information about points selected by the LinkedBrush plugin. I think my question is sort of related to this example. I have meta information tied to each point via the HTMLTooltip plugin. Ideally, I would somehow be able to dump this too. In the example I linked to, the information is outputted via a prompt. I wish to be able to save this information to a text file of some kind.
Put slightly differently: How do I determine which points in a scatter plot have been selected by the LinkedBrush tool so that I can save the information?
To solves this, I ended up just editing the LinkedBrush plugin code. I added a button that, when clicked, outputs the extent of the brush window by using brush.extent(). This prints the minimum and maximum x and y coordinates. I will basically use these coordinates to trace back to the input data set and determine which points fell within the bounds of the brush. If anyone has a better idea of how to solve this, I would welcome it.
class LinkedBrush(plugins.PluginBase):
JAVASCRIPT="""
mpld3.LinkedBrushPlugin = mpld3_LinkedBrushPlugin;
mpld3.register_plugin("linkedbrush", mpld3_LinkedBrushPlugin);
mpld3_LinkedBrushPlugin.prototype = Object.create(mpld3.Plugin.prototype);
mpld3_LinkedBrushPlugin.prototype.constructor = mpld3_LinkedBrushPlugin;
mpld3_LinkedBrushPlugin.prototype.requiredProps = [ "id" ];
mpld3_LinkedBrushPlugin.prototype.defaultProps = {
button: true,
enabled: null
};
function mpld3_LinkedBrushPlugin(fig, props) {
mpld3.Plugin.call(this, fig, props);
if (this.props.enabled === null) {
this.props.enabled = !this.props.button;
}
var enabled = this.props.enabled;
if (this.props.button) {
var BrushButton = mpld3.ButtonFactory({
buttonID: "linkedbrush",
sticky: true,
actions: [ "drag" ],
onActivate: this.activate.bind(this),
onDeactivate: this.deactivate.bind(this),
onDraw: function() {
this.setState(enabled);
},
icon: function() {
return mpld3.icons["brush"];
}
});
this.fig.buttons.push(BrushButton);
var my_icon = "data:image/png;base64,longstring_that_I_redacted";
var SaveButton = mpld3.ButtonFactory({
buttonID: "save",
sticky: false,
onActivate: this.get_selected.bind(this),
icon: function(){return my_icon;},
});
this.fig.buttons.push(SaveButton);
}
this.extentClass = "linkedbrush";
}
mpld3_LinkedBrushPlugin.prototype.activate = function() {
if (this.enable) this.enable();
};
mpld3_LinkedBrushPlugin.prototype.deactivate = function() {
if (this.disable) this.disable();
};
mpld3_LinkedBrushPlugin.prototype.get_selected = function() {
if (this.get_selected) this.get_selected();
};
mpld3_LinkedBrushPlugin.prototype.draw = function() {
var obj = mpld3.get_element(this.props.id);
if (obj === null) {
throw "LinkedBrush: no object with id='" + this.props.id + "' was found";
}
var fig = this.fig;
if (!("offsets" in obj.props)) {
throw "Plot object with id='" + this.props.id + "' is not a scatter plot";
}
var dataKey = "offsets" in obj.props ? "offsets" : "data";
mpld3.insert_css("#" + fig.figid + " rect.extent." + this.extentClass, {
fill: "#000",
"fill-opacity": .125,
stroke: "#fff"
});
mpld3.insert_css("#" + fig.figid + " path.mpld3-hidden", {
stroke: "#ccc !important",
fill: "#ccc !important"
});
var dataClass = "mpld3data-" + obj.props[dataKey];
var brush = fig.getBrush();
var dataByAx = [];
fig.axes.forEach(function(ax) {
var axData = [];
ax.elements.forEach(function(el) {
if (el.props[dataKey] === obj.props[dataKey]) {
el.group.classed(dataClass, true);
axData.push(el);
}
});
dataByAx.push(axData);
});
var allData = [];
var dataToBrush = fig.canvas.selectAll("." + dataClass);
var currentAxes;
function brushstart(d) {
if (currentAxes != this) {
d3.select(currentAxes).call(brush.clear());
currentAxes = this;
brush.x(d.xdom).y(d.ydom);
}
}
function brushmove(d) {
var data = dataByAx[d.axnum];
if (data.length > 0) {
var ix = data[0].props.xindex;
var iy = data[0].props.yindex;
var e = brush.extent();
if (brush.empty()) {
dataToBrush.selectAll("path").classed("mpld3-hidden", false);
} else {
dataToBrush.selectAll("path").classed("mpld3-hidden", function(p) {
return e[0][0] > p[ix] || e[1][0] < p[ix] || e[0][1] > p[iy] || e[1][1] < p[iy];
});
}
}
}
function brushend(d) {
if (brush.empty()) {
dataToBrush.selectAll("path").classed("mpld3-hidden", false);
}
}
this.get_selected = function(d) {
var brush = fig.getBrush();
var extent = brush.extent();
alert(extent);
}
this.enable = function() {
this.fig.showBrush(this.extentClass);
brush.on("brushstart", brushstart).on("brush", brushmove).on("brushend", brushend);
this.enabled = true;
};
this.disable = function() {
d3.select(currentAxes).call(brush.clear());
this.fig.hideBrush(this.extentClass);
this.enabled = false;
};
this.disable();
};
"""
def __init__(self, points, button=True, enabled=True):
if isinstance(points, mpl.lines.Line2D):
suffix = "pts"
else:
suffix = None
self.dict_ = {"type": "linkedbrush",
"button": button,
"enabled": False,
"id": utils.get_id(points, suffix)}
I am not a programmer or a developer. I am facing a problem that the google map infobox not display when they are in exact same location, (geocodezip) have a very good solution, however I don't know how to modify my code.
This is my code
(function ($) {
var settings;
var element;
var map;
var markers = new Array();
var markerCluster;
var clustersOnMap = new Array();
var clusterListener;
var methods = {
init: function (options) {
element = $(this);
var defaults = $.extend({
enableGeolocation: false,
pixelOffsetX : -145,
pixelOffsetY : -200
});
settings = $.extend({}, defaults, options);
google.maps.Map.prototype.setCenterWithOffset = function (latlng, offsetX, offsetY) {
var map = this;
var ov = new google.maps.OverlayView();
ov.onAdd = function () {
var proj = this.getProjection();
var aPoint = proj.fromLatLngToContainerPixel(latlng);
aPoint.x = aPoint.x + offsetX;
aPoint.y = aPoint.y + offsetY;
map.setCenter(proj.fromContainerPixelToLatLng(aPoint));
}
ov.draw = function () {
};
ov.setMap(this);
};
google.maps.visualRefresh = true;
google.maps.event.addDomListener(window, 'load', loadMap);
if (settings.filterForm && $(settings.filterForm).length !== 0) {
$(settings.filterForm).submit(function (e) {
var form = $(this);
var action = $(this).attr('action');
$.ajax({
type : 'GET',
url : action,
data : form.serialize(),
success: function (data) {
element.aviators_map('removeMarkers');
element.aviators_map('addMarkers', {
locations: eval(data.locations),
types : eval(data.types),
contents : eval(data.contents)
});
}
});
e.preventDefault();
});
}
if (options.callback) {
options.callback();
}
return $(this);
},
removeMarkers: function () {
for (i = 0; i < markers.length; i++) {
markers[i].infobox.close();
markers[i].marker.close();
markers[i].setMap(null);
}
markerCluster.clearMarkers();
$.each(clustersOnMap, function (index, cluster) {
cluster.cluster.close();
});
clusterListener.remove();
},
addMarkers: function (options) {
markers = new Array();
settings.locations = options.locations;
settings.contents = options.contents;
settings.types = options.types;
renderElements();
}
}
$.fn.aviators_map = function (method) {
// Method calling logic
if (methods[method]) {
return methods[ method ].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on Aviators Map');
}
};
function loadMap() {
var mapOptions = {
zoom : settings.zoom,
mapTypeId : google.maps.MapTypeId.ROADMAP,
scrollwheel : false,
draggable : true,
mapTypeControl : false,
panControl : false,
zoomControl : true,
zoomControlOptions: {
style : google.maps.ZoomControlStyle.SMALL,
position: google.maps.ControlPosition.LEFT_BOTTOM
}
};
if (settings.enableGeolocation) {
if (navigator.geolocation) {
browserSupportFlag = true;
navigator.geolocation.getCurrentPosition(function (position) {
initialLocation = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
map.setCenter(initialLocation);
}, function () {
mapOptions.center = new google.maps.LatLng(settings.center.latitude, settings.center.longitude);
});
} else {
browserSupportFlag = false;
mapOptions.center = new google.maps.LatLng(settings.center.latitude, settings.center.longitude);
}
} else {
mapOptions.center = new google.maps.LatLng(settings.center.latitude, settings.center.longitude);
}
map = new google.maps.Map($(element)[0], mapOptions);
var dragFlag = false;
var start = 0, end = 0;
function thisTouchStart(e) {
dragFlag = true;
start = e.touches[0].pageY;
}
function thisTouchEnd() {
dragFlag = false;
}
function thisTouchMove(e) {
if (!dragFlag) {
return
}
end = e.touches[0].pageY;
window.scrollBy(0, ( start - end ));
}
var el = $('#map')[0];
if (el.addEventListener) {
el.addEventListener('touchstart', thisTouchStart, true);
el.addEventListener('touchend', thisTouchEnd, true);
el.addEventListener('touchmove', thisTouchMove, true);
} else if (el.attachEvent){
el.attachEvent('touchstart', thisTouchStart);
el.attachEvent('touchend', thisTouchEnd);
el.attachEvent('touchmove', thisTouchMove);
}
google.maps.event.addListener(map, 'zoom_changed', function () {
$.each(markers, function (index, marker) {
marker.infobox.close();
marker.infobox.isOpen = false;
});
});
renderElements();
$('.infobox .close').live('click', function () {
$.each(markers, function (index, marker) {
marker.infobox.close();
marker.infobox.isOpen = false;
});
});
}
function isClusterOnMap(clustersOnMap, cluster) {
if (cluster === undefined) {
return false;
}
if (clustersOnMap.length == 0) {
return false;
}
var val = false;
$.each(clustersOnMap, function (index, cluster_on_map) {
if (cluster_on_map.getCenter() == cluster.getCenter()) {
val = cluster_on_map;
}
});
return val;
}
function addClusterOnMap(cluster) {
// Hide all cluster's markers
$.each(cluster.getMarkers(), (function () {
if (this.marker.isHidden == false) {
this.marker.isHidden = true;
this.marker.close();
}
}));
var newCluster = new InfoBox({
markers : cluster.getMarkers(),
draggable : true,
content : '<div class="clusterer"><div class="clusterer-inner">' + cluster.getMarkers().length + '</div></div>',
disableAutoPan : true,
pixelOffset : new google.maps.Size(-21, -21),
position : cluster.getCenter(),
closeBoxURL : "",
isHidden : false,
enableEventPropagation: true,
pane : "mapPane"
});
cluster.cluster = newCluster;
cluster.markers = cluster.getMarkers();
cluster.cluster.open(map, cluster.marker);
clustersOnMap.push(cluster);
}
function renderElements() {
$.each(settings.locations, function (index, location) {
var marker = new google.maps.Marker({
position: new google.maps.LatLng(location[0], location[1]),
map : map,
icon : settings.transparentMarkerImage
});
marker.infobox = new InfoBox({
content : settings.contents[index],
disableAutoPan : false,
maxWidth : 0,
pixelOffset : new google.maps.Size(settings.pixelOffsetX, settings.pixelOffsetY),
zIndex : null,
closeBoxURL : "",
infoBoxClearance : new google.maps.Size(1, 1),
position : new google.maps.LatLng(location[0], location[1]),
isHidden : false,
pane : "floatPane",
enableEventPropagation: false
});
marker.infobox.isOpen = false;
marker.marker = new InfoBox({
draggable : true,
content : '<div class="marker ' + settings.types[index] + '"><div class="marker-inner"></div></div>',
disableAutoPan : true,
pixelOffset : new google.maps.Size(-21, -58),
position : new google.maps.LatLng(location[0], location[1]),
closeBoxURL : "",
isHidden : false,
pane : "floatPane",
enableEventPropagation: true
});
marker.marker.isHidden = false;
marker.marker.open(map, marker);
markers.push(marker);
google.maps.event.addListener(marker, 'click', function (e) {
var curMarker = this;
$.each(markers, function (index, marker) {
// if marker is not the clicked marker, close the marker
if (marker !== curMarker) {
marker.infobox.close();
marker.infobox.isOpen = false;
}
});
if (curMarker.infobox.isOpen === false) {
curMarker.infobox.open(map, this);
curMarker.infobox.isOpen = true;
map.setCenterWithOffset(curMarker.getPosition(), 100, -120);
} else {
curMarker.infobox.close();
curMarker.infobox.isOpen = false;
}
});
});
markerCluster = new MarkerClusterer(map, markers, {
gridSize: 40,
styles: [
{
height : 42,
url : settings.transparentClusterImage,
width : 42,
textColor: 'transparent'
}
]
});
clustersOnMap = new Array();
clusterListener = google.maps.event.addListener(markerCluster, 'clusteringend', function (clusterer) {
var availableClusters = clusterer.getClusters();
var activeClusters = new Array();
$.each(availableClusters, function (index, cluster) {
if (cluster.getMarkers().length > 1) {
activeClusters.push(cluster);
}
});
$.each(availableClusters, function (index, cluster) {
if (cluster.getMarkers().length > 1) {
var val = isClusterOnMap(clustersOnMap, cluster);
if (val !== false) {
val.cluster.setContent('<div class="clusterer"><div class="clusterer-inner">' + cluster.getMarkers().length + '</div></div>');
val.markers = cluster.getMarkers();
$.each(cluster.getMarkers(), (function (index, marker) {
if (marker.marker.isHidden == false) {
marker.marker.isHidden = true;
marker.marker.close();
}
}));
} else {
addClusterOnMap(cluster);
}
} else {
// Show all markers without the cluster
$.each(cluster.getMarkers(), function (index, marker) {
if (marker.marker.isHidden == true) {
marker.marker.open(map, this);
marker.marker.isHidden = false;
}
});
// Remove old cluster
$.each(clustersOnMap, function (index, cluster_on_map) {
if (cluster !== undefined && cluster_on_map !== undefined) {
if (cluster_on_map.getCenter() == cluster.getCenter()) {
// Show all cluster's markers/
cluster_on_map.cluster.close();
clustersOnMap.splice(index, 1);
}
}
});
}
});
var newClustersOnMap = new Array();
$.each(clustersOnMap, function (index, clusterOnMap) {
var remove = true;
$.each(availableClusters, function (index2, availableCluster) {
if (availableCluster.getCenter() == clusterOnMap.getCenter()) {
remove = false;
}
});
if (!remove) {
newClustersOnMap.push(clusterOnMap);
} else {
clusterOnMap.cluster.close();
}
});
clustersOnMap = newClustersOnMap;
});
}
})(jQuery);
and This is geocodezip code
Google Maps Multiple markers with the exact same location Not working
Many Many Thanks
That solution is great, but I'd take a look at using the Overlapping Marker Spiderfier library to handle markers in the same location. You can use this in conjunction with the marker clusterer library, without any issues. This way you also don't lose the ability to see how many markers are actually in that same location - and it gives you a great UI in my opinion.
To use Overlapping Marker Spiderfier, include the script file before your main js file in your html. Then in your js, create an instance of the OverlappingMarkerSpiderfier object:
var oms = new OverlappingMarkerSpiderfier(map);
/*in your case I'd do this after you initialize the `map` object,
*and declare the `oms` globally, like you do with your other global objects
*/
Then when the markers are created, you want to add the marker to the oms object via the addMarker() method. So, in your case add the following line to the renderElements() function after the click event listener you declare for the marker:
oms.addMarker(marker);
Lastly, make sure to also clear the markers from the oms object when the removeMarkers() function in your code is called by adding the following to that function:
oms.clearMarkers();