Call map.setView for javascript from a function with variables - javascript

I am running a django app with tables2. I then set up a field with linkify where i want to zoom to a feature by running a javascript function.
My code in the renderd htm is:
<div id="map" class="leaflet-container-default"></div>
......
<td >Zoom til</td>....
<script type="text/javascript">
function myFunction(lat,long) {
map.setView([lat,long], 15);
}
</script>
Django laflet generatet map script where the map is defined:
<script>
(function () {
function loadmap() {
var djoptions = {"srid": null, "extent": [[-90, -180], [90, 180]], "fitextent": true, "center": [61.2340642364768, 7.10221073722647], "zoom": 12 },
options = {djoptions: djoptions, initfunc: loadmap,
globals: false, callback: window.map_init},
map = L.Map.djangoMap('map', options);
}
var loadevents = ["load"];
if (loadevents.length === 0) loadmap();
else if (window.addEventListener) for (var i=0; i<loadevents.length; i++) window.addEventListener(loadevents[i], loadmap, false);
else if (window.jQuery) jQuery(window).on(loadevents.join(' '), loadmap);
})();
</script>

The map variable shown in the code snippet is internal to the inner scope of the loadmap function. Therefore you can no longer access it later on.
There is probably a way to retrieve it through Django Leaflet API.
Otherwise, if you can have a script executed before Django Leaflet one, you can setup a Leaflet init hook ehich can provide you with the map reference. See Find Leaflet map object after initialisation

Related

Google Geochart visualization library not loaded

I have created a Google Geochart widget some time ago with an older Google JS library version. Nowadays Google advised to upgrade to update to the loader api instead of the jsapi. No matter how I load the libraries, for me the visualization library doesn't load properly, hence I get an undefined when trying to instantiate a GeoChart object. Did anybody else encounter this issue as well?
(The JS code is in the form of Dojo widget functions)
update : function(obj, callback){
this._contextObj = obj;
this._resetSubscriptions();
if (this.apiAccessKey && this.apiAccessKey !== "") {
google.charts.load('current', {
'packages':['geochart'],
// Note: you will need to get a mapsApiKey for your project.
// See: https://developers.google.com/chart/interactive/docs/basic_load_libs#load-settings
'mapsApiKey': this.apiAccessKey
});
google.charts.setOnLoadCallback(this.drawChart(callback));
} else {
var message = " Google Geochart needs an active API key to work!";
console.error(this._logNode + message);
alert(message);
}
},
drawChart : function (callback) {
// Run this as soon as google charts is loaded.
// Create map and its container.
if (!this.geoMap) {
this.geoMap = new google.visualization.GeoChart(this.geoMapContainer);
}
if (this._contextObj){
this._getObjects(this._contextObj.getGuid,callback);
} else {
this._getObjects(null,callback);
}
this._executeCallback(callback);
},
setOnLoadCallback expects a reference to a function --> this.drawChart
not the result of a function --> this.drawChart(callback)
try as follows...
google.charts.setOnLoadCallback(function () {
this.drawChart(callback);
});

How can I create an ionic popover from a leafletjs polygon?

I am using Leaflet JS to draw polygons on a map.
I am able to draw the shapes, and to save the shapes to a database as GeoJSON like this:
.ts file
...
let layer = event.layer;
let geometry = layer.toGeoJSON();
this.drawLayer.addLayer(layer);
}
I call a method in the ngOnInit method to redraw the shapes:
drawPolygonShape(data) {
if (data.polygon.geometry) {
let shape = {
type: data.polygon.type,
geometry: {
type: data.polygon.geometry.type,
coordinates: data.polygon.geometry.coordinates
},
properties: {}
};
L.geoJSON(shape, {
onEachFeature: this.onEachFeature
}).addTo(this.myMap);
}
}
...
onEachFeature(feature, layer) {
layer.on('click', event => {
// layer.bindPopup('Hello World'); // Works great
let popover = this.popoverCtrl.create('MyComponent', { layer: layer });
popover.present();
});
}
I am importing MyComponent into the module file, so I know it is available. However, I am always getting the following error message:
Cannot read property 'create' of undefined
So, somewhere there is a timing or scope problem that is not correctly working with the click event.
It seems like a scope problem, as any component gives the same error. Any suggestions are greatly appreciated!
EDIT
Thank you to #ghybs I've tried adding this as a third argument to the click event, but I'm still getting the same error:
onEachFeature(feature, layer) {
layer.on('click', event => {
// layer.bindPopup('Hello World'); // Works great
let popover = this.popoverCtrl.create('MyComponent', { layer: layer });
popover.present();
}, this);
}
EDIT 2
Thank you #ghybs!
I'm curious about your second suggestion - I am setting up the map like this:
let mapOptions: any = {
position: 'topright',
draw: {
polyline: false,
...
}
}
...
let drawControl = new L.Control.Draw(mapOptions);
this.myMap.addControl(drawControl);
this.myMap.on(L.Draw.Event.CREATED, this.onCreatePolygon.bind(this));
The .bind(this) makes more sense now - onCreatePolygon is a method I am using to save the shape.
How do you suggest I delegate to the click event for each shape?
this.myMap.on(L.Draw.Event.CLICK, this.MYCLICKHANDLER.bind(this));
(it's obvious I'm not familiar working with this so I appreciate all of your time.)
In your case you have a double context issue since you also pass your onEachFeature method that will get invoked with a this context that is already different from your class instance.
You could do onEachFeature: this.onEachFeature.bind(this) together with your layer.on("click", cb, this)
You could also use event delegation by attaching the listener on your GeoJSON Layer Group instead of each individual feature, so that you get rid of one of the context:
var geoJsonData = {
"type": "Point",
"coordinates": [2.35, 48.86]
};
class Component {
constructor(mapId) {
this.myMap = L.map(mapId).setView([48.86, 2.35], 11);
L.geoJSON(geoJsonData).addTo(this.myMap).on("click", event => {
console.log(event.target); // this is the GeoJSON Layer Group.
console.log(event.layer); // this is the individual child feature.
let popover = this.popoverCtrl.create('MyComponent');
popover.present();
}, this); // Not even needing the 3rd arg since you use a fat arrow function, which does not have its own context.
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(this.myMap);
}
}
Component.prototype.popoverCtrl = { // Dummy popoverCtrl
create(content) {
dummyPopoverContent = content;
return {
present() {
alert(dummyPopoverContent);
},
};
},
};
var dummyPopoverContent = '';
new Component('map');
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.1/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.3.1/dist/leaflet-src.js" integrity="sha512-IkGU/uDhB9u9F8k+2OsA6XXoowIhOuQL1NTgNZHY1nkURnqEGlDZq3GsfmdJdKFe1k1zOc6YU2K7qY+hF9AodA==" crossorigin=""></script>
<div id="map" style="height: 180px"></div>
See also start a function when click on circle - leaflet
As for your last question, with the 1st remark above you could re-write:
this.myMap.on(L.Draw.Event.CREATED, this.onCreatePolygon.bind(this));
into:
this.myMap.on(L.Draw.Event.CREATED, this.onCreatePolygon, this);
Event delegation does not seem relevant in this case since you already attach a single listener on your map, not on individual layers.

Google Earth API doesn't create place mark I want

I'm making an ASP.net app to show some features on Google Earth.
After reading "Google's Developer Guide" now i'm using this javascript code:
<script type="text/javascript" src="http://www.google.com/jsapi?hl=en&key=MyAPIKey"></script>
<script type="text/javascript">
var ge;
google.load("earth", "1", {"other_params": "sensor=true_or_false"});
function init() {
google.earth.createInstance('map3d', initCB, failureCB);
}
function initCB(instance) {
ge = instance;
ge.getWindow().setVisibility(true);
}
function failureCB(errorCode) {
}
function generator() {
// Create the placemark.
var placemark = ge.createPlacemark('');
placemark.setName("placemark");
// Set the placemark's location.
var point = ge.createPoint('');
point.setLatitude(12.345);
point.setLongitude(54.321);
placemark.setGeometry(point);
// Add the placemark to Earth.
ge.getFeatures().appendChild(placemark);
alert('OK!');
}
google.setOnLoadCallback(init);
</script>
Then have a code like this in c# to run javascript:
b.ID = "btnSomeButton";
b.Text = "Click to generate PlaceMark!";
b.Attributes.Add("onclick", "return generator();");
My page displays the Google Earth but when I click on the button it doesn't create place mark.Where I am wrong?
I dont know what mistake in your program. It may be created successfully. I think you are searching somewhere. After placemark creation try to change your camera view. Try this code after placemark creation:
var lookAt = ge.getView().copyAsLookAt(ge.ALTITUDE_RELATIVE_TO_GROUND);
lookAt.setLatitude(12.345);
lookAt.setLongitude(54.321);
lookAt.setAltitude(1000);
ge.getView().setAbstractView(lookAt);
It may work. I'm not sure.

I can't get a kml file loaded with ge plugin to move to the last lat/lon

I have a web page that loads a kml file for viewing using the Google Earth ge plugin. The file loads and displays fine. However, I can get the plugin to move to a lat/lon at the end of the file. The load always leaves the camera at the lat/lon that corresponds to the end point of the kml file.
Here's the code:
var ge;
google.load("earth", "1");
google.load("maps", "2");
function init() {
google.earth.createInstance('map3d', initCallback, failureCallback);
}
function initCallback(instance) {
ge = instance;
ge.getWindow().setVisibility(true);
ge.getNavigationControl().setVisibility(ge.VISIBILITY_AUTO);
ge.getLayerRoot().enableLayerById(ge.LAYER_BORDERS, true);
ge.getLayerRoot().enableLayerById(ge.LAYER_ROADS, true);
ge.getOptions().setFlyToSpeed(ge.SPEED_TELEPORT);
var url = 'http://rallyroadie.org/wordpress/ge/vladi_finish.kml';
google.earth.fetchKml(ge, url, finished);
}
function finished(object) {
if (!object) {
setTimeout(function() {
alert('Bad or null KML.');
}, 0);
return;
}
ge.getFeatures().appendChild(object);
var lookAt = ge.getView().copyAsLookAt(ge.ALTITUDE_RELATIVE_TO_GROUND);
// Set new latitude and longitude values.
lookAt.setLatitude(43.023157);
lookAt.setLongitude(131.853040);
// Update the view in Google Earth.
ge.getView().setAbstractView(lookAt);
}
function failureCallback(errorCode) {
}
google.setOnLoadCallback(init);
You can see the page at http://rallyroadie.org/wordpress/ge/vladi.html
TIA,
Paul
Are you wanting to know how to set the initial view? If so:
You are currently setting it with this code -
var lookAt = ge.getView().copyAsLookAt(ge.ALTITUDE_RELATIVE_TO_GROUND);
// Set new latitude and longitude values.
lookAt.setLatitude(43.023157);
lookAt.setLongitude(131.853040);
// Update the view in Google Earth.
ge.getView().setAbstractView(lookAt);
Try playing with different Latitude and Longitude numbers and you will see the difference.
You can also use stuff like lookAt.setRange, lookAt.setTilt and lookAt.setAltitude
See this link for more details
It has nothing to do with the .kml file you loaded.

Google annotated timeline not displaying on application start

I am having a problem with the Google annotated timeline. I have this function (shown below) that is called in the jQuery ready function:
//creates an annotated timeline
function graphAnnotatedTimeLine(url) {
jQuery.get(url, function(returned_data) {
//parse returned_data ...
//build data table
var dataTable = new google.visualization.DataTable();
dataTable.addColumn('datetime', columnHeadings[0]);
dataTable.addColumn('number', columnHeadings[1]);
//populate table
for(var i = 0; i < rawData.length; i++) {
var parsedData = data[i].split(",");
dataTable.addRow([new Date(parsedData[0]), parseFloat(parsedData[1])]);
}
//draw graph
var options = {displayAnnotations: false,
allowRedraw: true,
legendPosition: 'newRow',
displayZoomButtons: false,
wmode: 'transparent'};
var chart = new google.visualization.AnnotatedTimeLine(document.getElementById('chart-div'));
chart.draw(dataTable, options);
});
}
Called in the ready function as:
$.ready(function() {
//generate url string
google.setOnLoadCallback(graphAnnotatedTimeline(url));
self.setInterval('updateGraph', 60000);
//more stuff
});
So in the ready I call it to draw the first set of data and then set an update function to be called every minute. All the update function does is basically the same as the ready function does: build a url string and call the graph function with that url. The problem I'm having is that the graph it doesn't display on startup. Once the update gets called once though, it displays fine after that. Is there anyone that can give me some insite as to why this is happening?
This is because your jquery ready function is called before the google visualization script is loaded. google.setOnLoadCallback must be called like this...
<script type="text/javascript" src='http://www.google.com/jsapi?autoload={"modules":[{"name":"visualization","version":"1","packages":["annotatedtimeline"]}]}'></script>
<script type="text/javascript">
google.setOnLoadCallback(graphAnnotatedTimeline(url));
</script>

Categories