Javascript or jQuery png player - javascript

I am using a mapping app called Leaflet. Some of the code I use is below:
var layer1 =L.tileLayer('http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/7540/256/{z}/{x}/{y}.png', {
attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © CloudMade',
maxZoom: 12
}).addTo(map);
// THE ABOVE CODE MERELY PLACES A BASE LAYER INSIDE A DIV TAG. But the key to this is the //addTo method.
I also am getting weather radar data from Aeris and create a layer on leaflet using this:
var radar_img_arr = createVariables();
and the createVariables() looks like this:
function createVariables(){
var radar_images = [];
for (var i = 0; i <= 99; ++i) {
radar_images[i] = L.tileLayer('http://tile2.aerisapi.com/QjvmoFnKc1Wj94aDULEX_8Y7R8eagwQKlUusR5WZk6JTBdz6zlCm3KIP15CLG/radar/{z}/{x}/{y}/'+data.files[i].time +'.png', {opacity: 0.6, format: 'image/png', maxZoom: 12,attribution: "FOSM"}).addTo(map).setZIndex(999);
}
return radar_images;
}
The above adds to the map all data to the map at once just to test.
What I really want is a loop which can remove a old layer from the map and replace it with a new layer.
The 2 important methods are below:
map.removeLayer(radar_img_arr[i]);
map.addLayer(radar_img_arr[i+1]);
I am trying to write a loop to do this and the timing is messed up. other weather sites use Flex or Flash to animate a radar loop but i want to try a Javascript solution.
Does anyone know how to create this loop in JS or jQuery?
Thanks,
Jim

You should use set timeout to iterate over the loop... Something like:
// function for setTimeout
var updateImage = function() {
//gets the current image & update place
var img = radar_img_arr[place++]
// code to update display here.
...
// call the function again in 1 second
setTimeout(updateImage, 1000)
// reset place to 0 if need be
if (step == radar_img_arr.length-1)
place = 0;
}
// variable to store where we are in the array.
var place = 0
// array of images
var radar_img_arr = createVariables()
//start the process in 1 second:
setTimeout(updateImage, 1000)
// or, start it right away:
updateImage()
I don't like to use setInterval, which will automatically call your function over and over however many miliseconds you pass. Reason is, if your function takes longer to run than timer takes, you create a race condition, which in your case would cause the images to update strangely.

Related

How to update popup content using leaflet and Ajax (Part 2)

This question is the "episode 2" of this: Original question
Hi !
I'm still having trouble with my map. In fact, I believed the solution in the link above had solve my problem, but I figured out another problem.
My code and my aim are almost the same as the "episode 1" of this question.
As a reminder, I have a Leaflet map that uses MarkerCluster to show ~36.000 markers. Each marker must have a Popup (that appear onclick) which contains many informations.
As they were too many informations to get at one time (I mean to get all points and all informations at one time), I had the idea to get latitude, longitude and a single ID in order to show the Markers on the map. Next, when click on a Popup, the script make an Ajax request to get infos from a Database, using the single ID contains by each marker.
For now, and with the great help of maximkou, I can make this happen. My problem is, that only the last ID is consider, so it always request on the same ID and always show the same information (which is not what I try to do).
I tried many things (like getting all the markers on the map, trying to put markers on an array, etc.) but I can't figure out how to get this work.
I don't think it's impossible (but maybe it is), I think I simply lack skill on Javascript.
If you have another solution or idea, I will be glad to test it to !
I will now show you an extract of my current code:
function makeMap(pointsToInsert){
if (typeof map != 'undefined') {
map.off();
map.remove();
}
var tiles=L.tileLayer('https://api.mapbox.com/styles/v1/mapbox/streets-v9/tiles/256/{z}/{x}/{y}?access_token=', {
attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © Mapbox',
maxZoom: 20,
}),
latlng = L.latLng(48.8557, 2.3600);
var map = L.map('map', {center: latlng, zoom: 9, zoomControl:false, layers: [tiles]});
var arr = JSON.parse(pointsToInsert); //pointsToInsert come from a PHP script call before
var markers = L.markerClusterGroup();
for (var i = 0; i < arr.length; i++) {
var a = arr[i];
var ID = a[0];
var lat = a[1];
var lon = a[2];
var marker = L.marker(new L.LatLng(lat, lon));
marker.bindPopup(ID);
markers.addLayer(marker);
marker.on('click', function () {
var datas = marker.getPopup().getContent();
var popup = L.popup()
.setLatLng(this.getLatLng())
.setContent("Loading ...")
.openOn(map);
$.ajax({
url: 'getInfos.php',
type : 'POST',
data : "id=" + datas,
dataType: 'html',
success: function (data) {
popup.setContent(data);
},
error : function(resultat, statut, erreur){
alert("Error");
},
});
});
}
map.addLayer(markers);
}
I need some help here, please
If you want me to be more specific or to add others extract just let me know !
Thanks in advance

Displaying Map with Leaflet-Heat.js

I am currently working on a web application where I'm trying to display a heat map using the library called Leaflet.heat. It works with the Leaflet Javascript library to create an overlay heat map that looks pretty good. I feel like I'm pretty much there but having one last bit of trouble with array format and can't figure out what is wrong. Let me share the code that I have right now.
var mymap;
var marker = [];
var heatMapArr = [];
window.onload = function() {
alert("in initial func");
uponPageLoadDefault();
};
function uponPageLoadDefault()
{
//initial default page load
var branches = new L.LayerGroup();
var items = JSON.parse('${branches}');
var j = 0;
for(var i = 0; i < items.length; i++)
{
var LamMarker = new L.marker([items[i].lat, items[i].lon]);
//GOT RID OF FUNCTION CALL.
var heatMapPoint = {
lat: items[i].lat,
lon: items[i].lon,
intensity: items[i].tranCount
};
heatMapArr.push(heatMapPoint);
LamMarker.bindPopup("<b>" + items[i].branchName + "</b><br>" + items[i].branchAdd + "</br><br>" + items[i].branchCity + "</br><br>" + items[i].branchSt + "</br><br>" + items[i].branchZip + "</br><br>TranCount: " + items[i].tranCount).addTo(branches);
marker.push(LamMarker);
}
mbAttr = 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, ' +
'Imagery © Mapbox',
mbUrl = 'https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoidGFzdHlicm93bmllcyIsImEiOiJjaXgzZWxkaHowMWZhMnlvd2wzNHllaGwxIn0.0RSZEhtR0OBLMbwjqFfBkg';
var outdoors = L.tileLayer(mbUrl, {id: 'mapbox.outdoors', attribution: mbAttr});
var heatmap = L.heatLayer(heatMapArr, {radius: 6, blur: 8,maxZoom: 8});
var map = L.map('map', {
center: [39.73, -104.99],
zoom: 10,
layers: [outdoors, branches, heatmap]
});
var baseLayers = {
"Outdoors": outdoors
};
var overlays = {
"Branches": branches,
"HeatMap": heatmap
};
L.control.layers(baseLayers, overlays).addTo(map);
So basically I am trying to use the heat map display as a possible overlay that the user can select. The Leaflet-heat library tutorial is located at https://github.com/Leaflet/Leaflet.heat/ and it explains what needs to be done in order for the library to work.
Anyway, I have a list of items with latitude, longitude, and intensity amount, so I'm trying to use that, its called items. I iterate through that, pushing the select information into my heat map array. At this point I should be almost all set besides adding the overlays and creating the map. When I run the program, the map displays but the overlay icon is absent so there is an issue.
In the website tutorial they use a separate Javascript file which has an array of objects to create their heat map. I tried this with my program and then everything worked, which quickly led me to believe there's a problem with my array of objects, probably some minor formatting thing.......I am using another function to create an object with the data I have, so it will be in the same format as the website example.
I tried to use alert and other statements and compare my array to theirs but it hasn't yielded anything useful so I wanted to post my issue here on Stack to get some feedback from others on what could be wrong. I think its something really small that I may not be seeing.
Any feed back is greatly appreciated and certainly let me know if there's any questions.
Thanks!

How to change cluster zoom level on click with Leaflet map?

I have a leaflet map that has zoom levels 2-7 and uses the MarkerCluster plugin, by default I have the L.MarkerClusterGroup disable clustering a zoom level 2 (which means no clustering) and I'm trying to allow the user to click a button that then changes the clustering zoom level to 5. Is this possible?
I know I could do it by making two markercluster groups, one that has no clustering and one that has clustering and remove/add it based on click but that just seems incredibly messy. Really, there's several ways to do it but they are so incredibly clunky.
Code:
Default (2 is the lowest level of zoom):
var markers = new L.MarkerClusterGroup (
{
disableClusteringAtZoom: 2,
maxClusterRadius: 100,
animateAddingMarkers: true
});
What I want to do be able to do:
$('#mcluster').click(function() {
//do some code that sets the disableClusterAtZoom to 5
});
I could not find a way to disable clustering or set a new value for disableClustering at zoom, but I found a less clunky way of achieving this.
var markers = new L.LayerGroup(); //non cluster layer is added to map
markers.addTo(map);
var clusters = new L.MarkerClusterGroup (
{
disableClusteringAtZoom: 5,
maxClusterRadius: 100,
animateAddingMarkers: true
}); //cluster layer is set and waiting to be used
var clusterStatus = 'no'; //since non cluster group is on by default, the status for cluster is set to no
$('#mcluster').click(function( event ) {
if(clusterStatus === 'no'){
clusterStatus = 'yes';
var current1 = markers.getLayers(); //get current layers in markers
map.removeLayer(markers); // remove markers from map
clusters.clearLayers(); // clear any layers in clusters just in case
current1.forEach(function(item) { //loop through the current layers and add them to clusters
clusters.addLayer(item);
});
map.addLayer(clusters);
} else {
clusterStatus = 'no'; //we're turning off clustering here
var current2 = clusters.getLayers(); //same code as before just reversed
map.removeLayer(clusters);
markers.clearLayers();
current2.forEach(function(item) {
markers.addLayer(item);
});
map.addLayer(markers);
}
});
I'm sure there is a more elegant solution but with my still growing knowledge this is what I came up with.
I know you needed a solution a few months ago, but just to let you know that I released recently a sub-plugin for Leaflet.markercluster that can perform exactly what you are looking for (with a few extra code): Leaflet.MarkerCluster.Freezable (demo here).
var mcg = L.markerClusterGroup().addTo(map),
disableClusteringAtZoom = 2;
function changeClustering() {
if (map.getZoom() >= disableClusteringAtZoom) {
mcg.disableClustering(); // New method from sub-plugin.
} else {
mcg.enableClustering(); // New method from sub-plugin.
}
}
map.on("zoomend", changeClustering);
$('#mcluster').click(function () {
disableClusteringAtZoom = (disableClusteringAtZoom === 2) ? 5 : 2;
changeClustering();
});
mcg.addLayers(arrayOfMarkers);
// Initially disabled, as if disableClusteringAtZoom option were at 2.
changeClustering();
Demo: http://jsfiddle.net/fqnbwg3q/3/
Note: in the above demo I used a refinement to make sure the markers merge with animation when clustering is re-enabled. Simply use a timeout before using enableClustering():
// Use a timeout to trigger clustering after the zoom has ended,
// and make sure markers animate.
setTimeout(function () {
mcg.enableClustering();
}, 0);

unable to applyMatrix in three.js

I am trying to run an animation from a JSON file. I am using a custom JSON loader, (i.e. not the one included with three.js).
So I have an object named frames, which contain many frames, all of them have shape information, and a simulation_matrix, which contains data required for animation in the form of a 4by4 transformation matrix(generated from a python script).
So I am using this code for animation ..
and this is a sample JSON script to load.
// This method is for adding static shapes
// This works perfectly fine ..
parent.add_shape = function(frame)
{
var material = new THREE.MeshLambertMaterial({
color: frame.shape.color,
wireframe: true,
wireframeLinewidth: 0.1,
opacity: 0.5
})
var geometry = new THREE.CylinderGeometry(frame.shape.radius,frame.shape.radius,frame.shape.height,50,50);
// mesh_dict dictionary maps a mesh(shape) to its frame
parent.mesh_dict[frame] = new THREE.Mesh(geometry,material);
var init_orientation = frame.simulation_matrix[0];
var orienter = new THREE.Matrix4();
orienter.elements = [];
//Since simulation_matrix is generated from python, it is a
// list of lists, We need to push it to the elemens of Matrix4 manually ..
for(var i in init_orientation)
{
for(var j in init_orientation[i])
{
orienter.elements.push(init_orientation[i][j]) ;
}
}
parent.mesh_dict[frame].applyMatrix(new THREE.Matrix4());
parent.mesh_dict[frame].applyMatrix(orienter);
parent.scene.add(parent.mesh_dict[frame]);
parent.renderer.render(parent.scene,parent.camera);
}
// This method basically takes the meshes defined in add_shape, and
// applies simulation matrix to it, and requests animation frame for
// animation.
parent.animate = function()
{
for(var frame in JSONObj.frames)
{
// defining simulation_matrix in a var.
var matrix = JSONObj.frames[frame].simulation_matrix[parent.animation_counter];
var animation_matrix = new THREE.Matrix4();
animation_matrix.elements = [];
// pushing it to a Matrix4
for(var i in matrix)
{
for(var j in matrix[i])
{
animation_matrix.elements.push(matrix[i][j]) ;
}
}
console.log(animation_matrix);
console.log(animation_matrix.elements);
// Making sure we are not applying matrix to the earlier transform
//mesh_dict is a dictionary of meshes, used in creating shapes,mapped to the
//frame which contains them
parent.mesh_dict[JSONObj.frames[frame]].applyMatrix(new THREE.Matrix4());
// now applying transform, after setting to identity matrix ...
parent.mesh_dict[JSONObj.frames[frame]].applyMatrix(animation_matrix);
}
console.log(parent.animation_counter);
//update timestep ...
parent.animation_counter++;
// This is to loop over again and again ...
// assuming 10 animations frames
if(parent.animation_counter == 10){ parent.animation_counter = 0; }
requestAnimationFrame(parent.animate);
}
The problem is that I am able to create the multiple shapes, but when I apply simulation matrix to them in the loop, only one of them is animating, that too in very unexpected manner.
Well I have figured out what was wrong. Somehow, all the dictionary parent.mesh_dict[] keys were mapped to a same single object, instead of all objects as required. Now I debugged it, and it is working like a charm. Also your point is valid #WestLangley, as I now use mesh.matrix.identity() to get things done. Thanks, I will close this question now.

ArcGIS Javascript - Zoom to show all points

I am trying to add some functionality that will zoom the map in/out depending on the points that are returned from a query. So for example, say we're zoomed in on the state of Texas. If I execute a query and the service returns back points that are in Texas AND some located in California, I would like the map to then zoom out and then display both California and Texas. I have been looking through the ArcGIS JS API to see how I could implement it but I'm having trouble figuring out what properties and/or methods to use to accomplish this.
The FeatureSet provided to the QueryTask's onComplete callback has the property features that is an array of Graphics.
The javascript api provides the esri.graphicsExtent(graphics) function that can accept that array of Graphics and calculate their extent. Once the extent has been calculated, map.setExtent(extent) can be used to zoom the map to that extent.
It should be noted that the documentation for esri.graphicsExtent(...) specifies that 'If the extent height and width are 0, null is returned.' This case will occur if the returned Graphics array only has a single point in it, so you'll want to check for it.
Here's an example QueryTask onComplete callback that could be used to zoom the map to the extents of points returned by the query:
function onQueryComplete(returnedPointFeatureSet){
var featureSet = returnedPointFeatureSet || {};
var features = featureSet.features || [];
var extent = esri.graphicsExtent(features);
if(!extent && features.length == 1) {
// esri.getExtent returns null for a single point, so we'll build the extent by hand by subtracting/adding 1 to create x and y min/max values
var point = features[0];
extent = new esri.geometry.Extent(point.x - 1, point.y - 1, point.x + 1, point.y + 1, point.spatialReference);
}
if(extent) {
// assumes the esri map object is stored in the globally-scoped variable 'map'
map.setExtent(extent)
}
}
I agree, map.setExtent(extent, true) is the way to go here. Another observation: In case we have only a single point it's worth considering simply using map.centerAndZoom(point, ZOOM_LEVEL) instead of creating an extent. Then, we could just have this:
function onQueryComplete(returnedPointFeatureSet){
var featureSet = returnedPointFeatureSet || {};
var features = featureSet.features || [];
var extent = esri.graphicsExtent(features);
if(!extent && features.length == 1) {
var point = features[0];
map.centerAndZoom(point, 12);
}
else {
map.setExtent(extent, true);
}
}
Not a good idea to create an extent from a point that way. If the units are in degrees you could get a huge extent. Instead, you could do a buffer around the point using the geometryEngine
function onQueryComplete(featureSet){
if (featureSet.features.length) {
var extent = esri.graphicsUtils.graphicsExtent(featureSet.features);
if(!extent && featureSet.features.length == 1 && featureSet.features[0].geometry.type == "point") {
var point = featureSet.features[0];
var extent = esri.geometry.geometryEngine.buffer(point.geometry, 1, "meters").getExtent();
}
// assumes the esri map object is stored in the globally-scoped variable 'map'
map.setExtent(extent)
}
}

Categories

Resources