Leaflet map does not render tiles when route state change - javascript

I'm using leaflet to show some markers on map on my angular app.
When I first load the page the map shows ok, the problem is when I navigate to another page (with ui.router) and get back to the map page the tiles does not render anymore (all tiles are gray).
var map;
var all_coordinates;
function createMap(centrals) {
// create the tile layer with correct attribution
// set up the map
map = new L.Map('map', {
scrollWheelZoom: false
});
var baseMaps = {
"Real Image": esri,
"Roads": roads
};
roads.addTo(map);
all_coordinates = SOME_COORDINATES;
var overlayMaps = {"Name": SOME_LAYERS};
L.control.layers(baseMaps, overlayMaps).addTo(map);
//allCoordinates.push(L.latLng(37.016085, -7.933859));
map.fitBounds(all_coordinates).addLayer(centrals_layers);
return map;
}
Anyone has an ideia on what am I doing wrong?
EDIT:
Here is the route config for the map page:
$stateProvider
.state('home', {
url: "/home",
templateUrl: "/static/app/views/dashboard.html",
controller: "homeController",
resolve: {
loadPlugin: function ($ocLazyLoad) {
return $ocLazyLoad.load([
{
serie: true,
files: ['/static/vendor/datatables.net/js/jquery.dataTables.min.js',
'/static/vendor/datatables.net-bs/css/dataTables.bootstrap.min.css',
'/static/vendor/datatables.net-bs/js/dataTables.bootstrap.min.js']
},
{
serie: true,
name: 'datatables',
files: ['/static/vendor/angular-datatables/dist/angular-datatables.min.js',]
},
{
serie: true,
name: 'datatables.buttons',
files: ['/static/vendor/datatables.net-buttons/js/dataTables.buttons.min.js',
'/static/vendor/datatables.net-buttons-bs/css/buttons.bootstrap.min.css',
'/static/vendor/datatables.net-buttons-bs/js/buttons.bootstrap.min.js',
'/static/vendor/angular-datatables/dist/plugins/buttons/angular-datatables.buttons.min.js']
}
]);
}
}
})

Same problem as in Leaflet map loading half greyed tiles and related questions (e.g. Leaflet Map not showing in bootstrap div, Leaflet map not displayed properly inside tabbed panel, leaflet map shows up grey, etc etc) - just run map.invalidateSize() when your page layout is stable.

Related

Rails 7 importmap Stimulus controller configuration for OpenLayers?

Rails 7 importmap leaflet-css images path fix? showed how to get leaflet working in a Stimulus controller.
import { Controller } from "#hotwired/stimulus";
import "leaflet-css";
export default class extends Controller {
static targets = [ "trial" ]
connect(){
import("leaflet").then( L => {
this.map = L.map(this.trialTarget).setView([ 51.472814, 7.321673 ], 14);
var base_map = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap | SwmmGo',
transparency: true,
opacity: 0.5
}).addTo(this.map);
Can't figure out how to do this with OpenLayers. import("leaflet").then( L => { mapping is probably the key, but I don't understand what this is doing.
Beginning of controller:
import { Controller } from "#hotwired/stimulus";
export default class extends Controller {
static targets = [ "map" ]
connect(){
import("openlayers").then( ol => {
import GeoJSON from 'ol/format/GeoJSON';
etc.
Error is: controller: street (controllers/street_controller) SyntaxError: Unexpected identifier 'GeoJSON'
# config/importmaps.rb
pin "application", preload: true
pin "#hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "#hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "#hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true # Rail7 default also
pin_all_from "app/javascript/controllers", under: "controllers"
pin "jquery", to: "https://ga.jspm.io/npm:jquery#3.6.1/dist/jquery.js", preload: true
pin "popper", to: 'popper.js', preload: true
pin "bootstrap", to: 'bootstrap.min.js', preload: true
pin "leaflet", to: "https://ga.jspm.io/npm:leaflet#1.9.2/dist/leaflet-src.js", preload: true
pin "leaflet-css", to: "https://ga.jspm.io/npm:leaflet-css#0.1.0/dist/leaflet.css.min.js", preload: true
pin "leaflet.timeline", to: "https://ga.jspm.io/npm:leaflet.timeline#1.4.3/dist/index.js", preload: true
pin "openlayers", to: "https://ga.jspm.io/npm:openlayers#4.6.5/dist/ol.js"
This is a partial answer in that I changed to esbuild since it aligned better with node_modules and I could leverage some suggestions I saw for frameworks other than Rails. I made a simple controller to sort out the problems.
// app/javascript/controllers/ol_map_test_controller.js
import { Controller } from "#hotwired/stimulus"
import ol from 'openlayers/dist/ol.js'
// import Map from 'ol/Map' // does not work. Errors in compilation
export default class extends Controller {
static targets = [ "test" ] // is for Stimulus
connect() {
this.map = new ol.Map({
// this.map = new Map({
target: 'map', // #map defined separately from Stimulus target
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
}
}
and the HTML
<div id="map" data-controller="ol-map-test" data-ol-map-test-target="test" style="height:200px"></div>
Two things had to be done. Abandon defining Map from 'ol/Map' and associated wizardry of OpenLayers, i.e., not 'new Map'. One hopes that will get sorted out.
Secondly the div id has to be explicitly defined in HTML since Stimulus doesn't add that. The two targets could both be named map but for my sanity I named them differently.
Unfortunately this doesn't solve my problem as an OpenLayers module I need has the modern wizardry and doesn't compile the js.
I may see if this works with importmaps, but wanted to post this while I remembered what I had done.
One advantage to Stimulus is that one can easily experiment with other sample controllers with only one line of HTML.

Map layers do not render again past initial load

I am using VueMapbox (0.4.1) to utilize Mapbox GL in a Vue project.
<template>
<MglMap
:accessToken="accessToken"
:mapStyle.sync="mapStyle"
:repaint="true"
#load="onMapLoaded">
<MglMarker
:coordinates="someCoordinates"
class="map-marker-wrapper">
<div
slot="marker"
class="map-marker">
</div>
</MglMarker>
</MglMap>
</template>
<script>
import Mapbox from 'mapbox-gl'
import { MglMap, MglMarker } from 'vue-mapbox'
import * as MAP from '#/constants/map'
// Vue-Mapbox documentation: https://soal.github.io/vue-mapbox/guide/basemap.html#adding-map-component
export default {
name: 'Map',
components: {
MglMap,
MglMarker
},
props: {
someCoordinates: {
type: Array,
required: true
},
darkMode: {
type: Boolean,
required: true
}
},
data () {
return {
accessToken: MAP.ACCESS_TOKEN,
mapbox: null,
map: null,
actionsDispatcher: null
}
},
computed: {
mapStyle () {
return this.darkMode ? MAP.COLOR_PROFILES.DARK : MAP.COLOR_PROFILES.LIGHT
}
},
created () {
this.mapbox = Mapbox
},
methods: {
async onMapLoaded (event) {
this.map = event.map
this.actionsDispatcher = event.component.actions
await this.actionsDispatcher.flyTo({
center: this.someCoordinates
})
}
}
}
</script>
On the first load, everything works as expected:
But if I move to a different pseudo-route (say from /#/Map to /#/Profile and back), some of the map layers specified by my mapStyle (roads, city names,..) are not rendered anymore (default layers instead). The map also stops honoring any change of the mapStyle url, even when I specify mapStyle.sync in my template.
If I hit the browser's reload button it loads the layers as expected as the entire app is reloaded from scratch, but I unfortunately cannot afford to do this by default.
Any ideas are greatly appreciated.
I found a solution, in the example of vue-mapbox, the variable map (this.map) is set by "event.map" which causes an error because the card is not refreshed afterwards.
In my case i just remove that (this.map = event.map) in my onMapLoaded function and this is great.
Have a good day.
Despite I don’t know the syntax of Vue.js, the problem you are facing is that you are creating your layers in map.on('load', ... which is an event that happens only once, so when the style change happens, all the layers of the map style (including the ones created by custom code) are removed.
If you want to recreate your layers on style change, you have to do it in the event map.on('style.load', ..., but as said, I don’t see in your vue.js code where that is being done. If you share the part of the code where vue.js is invoking the methods it’ll be easier to help you

insert a url/path into google maps marker, Laravel

I am trying to insert a url/path into google map marker. So I tried google map's url: but no effects. when mouse on the marker it changes to pointer but I can't click or the page doesn't open.
By the way I try to make path to detail screen of each id.
var marker = new google.maps.Marker({
map: map,
icon: 'imgs/marker.png',
label: {
text: estates.data[0].price,
color: "#fff",
},
url: "/pages/{{$est->id}}",
position: {
lat: {{$est->lat}},
lng: {{$est->lng}}
}
});
The way I am using it wrong?
Controller:
public function details($id)
{
$estates = allestates::where('id', $id)->first();
// $rsltActualPrice = (int)$estates->extend / (int)$estates->price;
return view('pages.details', compact('estates'));
}
and Route:
Route::get('/pages/{id}', 'PagesController#details');
You may want to create a route like :
Route::get('/pages/{estateId}', 'yourController#index')->name('map');
and change your url address to this :
url: route('map', ['estateId' => $est->id]),

Using a Leaflet realtime layer in a markercluster group

I'm using Leaflet in combination with the realtime and markercluster plugins in order to show markers, that get live updated on a map.
The plugins work great independent from each other, but the problem arises when I want to cluster the realtime layer using the markercluster features.
Code sample for the realtime layer in which I convert the json to markers, asign a custom icon and apply some onEachFeature function:
realtimeLayer = L.realtime({
url: 'someURL',
crossOrigin: true,
type: 'json'
}, {
interval: 3 * 1000,
onEachFeature: onEachFeature,
pointToLayer: function(feature, latlng) {
return L.marker(latlng, {
icon: customIcon
});
}
});
What I'm able to do with non-realtime marker layers is to create a markercluster group and add the layer to it, so the markers get clustered like this:
var clusterGroup = L.markerClusterGroup();
clusterGroup.addLayer(someLayer);
However when I add the realtimeLayer to the clustergroup, the clustering is not applied, or the marker do net get loaded at all. What am I missing? Thanks!
You need to add the container option to your realtime object options.
From the official Leaflet Realtime documentation:
L.Realtime can also use other layer types to display the results, for
example it can use a MarkerClusterGroup from Leaflet MarkerCluster:
pass a LayerGroup (or any class that implements addLayer and
removeLayer) to L.Realtime's container option. (This feature was added
in version 2.1.0.)
https://github.com/perliedman/leaflet-realtime#overview
So after you initialize your cluster group and add it to map:
var clusterGroup = L.markerClusterGroup();
clusterGroup.addTo(map);
You can then pass the clusterGroup object to your realtime object in the container option:
realtimeLayer = L.realtime({
url: 'someURL',
crossOrigin: true,
type: 'json'
}, {
container: clusterGroup
interval: 3 * 1000,
onEachFeature: onEachFeature,
pointToLayer: function(feature, latlng) {
return L.marker(latlng, {
icon: customIcon
});
}
});
Now when you add the realtime object to the map, it should cluster correctly:
realtimeLayer.addTo(map)
The official Leaflet Realtime repo has an example for doing what you want with the added option of grouping multiple L.Realtime objects: https://github.com/perliedman/leaflet-realtime/blob/master/examples/earthquakes.js

using gmap3 to get location and plot route to known location - needs some fine tuning

i'm trying to use gmap3 to do the above but am running into difficulty. i can get 'map' to display and stick a marker on it. i'm still getting to grips with javascript and i'm sure some of my syntax is off which obviously doesn't help.
am i on the right track with regards to using geolocation to get the user's location and then plot the route to a predefined location?
apologies for incorrect syntax - i'm finding it hard to keep track brackets when using JS.
i'm using the example which can be found here: http://gmap3.net/api/add-directions-renderer.html
<script type="text/javascript">
$(function () {
//get the user's location
function getLocation(){
$('#map').gmap3({
action : 'geoLatLng',
callback : function(latLng){
if (latLng){
$(this).gmap3({
action: 'addMarker',
latLng:latLng
},
"autofit");
}
}
});
}
//plot directions
function plotRoute() {
$('#map').gmap3({
action: 'getRoute',
options:{
origin: 'latLang',
destination: 'Tallaght Business Park, Dublin, Ireland'
travelMode: google.maps.DirectionsTravelMode.DRIVING
},
callback: function(results){
if (!results) return;
$(this).gmap3({
action: 'init',
zoom: 13,
mapTyprId: google.maps.MapTypeId.ROADMAP,
streetViewControl: true
},
action: 'addDirectionsRenderer',
options: {
preserveViewPort: true,
draggable: true,
directions: results
}
);
}
});
}
});
</script>
to be placed in this div
<div class="gmap3" id="map"></div>

Categories

Resources