How to zoom gradually in leaflet, javascript - javascript

I use leaflet and geojson-vt too displaing map, and some lines in vector tiles. I made some modifications in geojson-vt because i need to add some my functions when tiles are slicing.
Everything works fine, when i start my leafletMap from zoom 1, and then increasing zoom by mouse wheel, to for example zoom=15. But There is a problem when i start my Map with zoom= for example 7,
var leafletMap = L.map('map').setView([52.00, 19.64], 7);
because the vector tiles are not beeing calcuated from 0 to 7, but only at 7, so "my function" dont working well.
I think that the solution will be to start map on zoom 0, and then in loop increasing zoom to 7. But i dont know how.
I tried this but it isn't working with multiple zooms...
setTimeout(function() {
leafletMap.setZoom(2);
}, 300);
...
setTimeout(function() {
leafletMap.setZoom(7);
}, 300);

Here is an example that shows how to zoom in gradually. Part of the problem with your code is that you called sequential setTimeout methods with the same delay and so they will be executed one right after another. If you change the milliseconds so that they increase (300, 600, 900, ...) then you will actually see the animated zoom.
This was quick example using OSM tiles and not geojson-vt, so it looks a little clunky until your browser caches the tiles. However, with geojson-vt you are creating your own local vector tiles and so it should be a bit smoother.
However, I'm not sure this will solve your problem because you didn't show the code you changed in geojson-vt. It may be that setZoom() isn't triggering your functions, but until you show those custom functions it will be hard to get a proper answer to your question.
var zoomDelayMs = 600; // milliseconds for animation delay
var maxZoom = 18;
var initialZoom = 7;
// Create the map
var map = L.map('map').setView([39.5, -0.5], initialZoom);
// Set up the OSM layer
var baseLayer = L.tileLayer(
'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: maxZoom
}).addTo(map);
// function to zoom in gradually from initialZoom to maxZoom
slowZoom = function() {
// reset zoom to default
var zoom = initialZoom;
map.setZoom(zoom);
// if already in middle of slow zoom, stop it
if (map.zoomtimer) clearInterval(map.zoomtimer);
// zoom in one level every zoomDelayMs
map.zoomtimer = setInterval(function() {
if (zoom < maxZoom)
map.setZoom(++zoom);
else {
clearInterval(map.zoomtimer);
map.zoomtimer = 0;
}
}, zoomDelayMs);
}
#map {
height: 400px;
}
input {
font-size: 1.6em;
}
<link href="https://npmcdn.com/leaflet#0.7.7/dist/leaflet.css" rel="stylesheet" />
<script src="https://npmcdn.com/leaflet#0.7.7/dist/leaflet.js"></script>
<input type='button' onclick='slowZoom()' value='Start slow zoom' />
<div id="map"></div>

Related

Leaflet - drawing semitransparent canvas tiles over map

I'm extending Leaflet's GridLayer to show canvas tiles on which I draw some data points - the problem is that after zooming in and out the other zoom layers are still visible, or are partially chopped off in random ways.
E.g. on the left is zoom level 13, on the right is after zooming out to 11 and back to 13 -
How can I show only the current zoom level, and prevent the canvas tiles from getting chopped off?
This is how I ended up fixing it, though there might be better ways...
Here's my GridCanvas class -
L.GridLayer.GridCanvas = L.GridLayer.extend({
onAdd: function (map) {
L.GridLayer.prototype.onAdd.call(this, map);
map.on('zoomend', e => this.onZoomEnd(e.target._zoom));
},
// on zoom end, want to hide all the tiles that are not on this zoom level,
// and show all the ones that are
onZoomEnd: function (zoom) {
Object.values(this._levels).forEach(level => {
level.el.style.display = (level.zoom === zoom) ? 'block' : 'none';
});
},
createTile,
});
The visibility of the tiles also gets set in seemingly random ways - this seemed to fix the problem - adding a class to the canvas elements and setting them to always be visible -
function createTile(coords, done) {
const canvas = L.DomUtil.create('canvas', 'grid-canvas-tile');
...
}
with styles.css:
.grid-canvas-tile {
visibility: visible !important;
}

Cesium: "fan out" overlapping polylines?

I am using Cesium and am looking to visually represent multiple polylines between the same two entities. For example, a green polyline from entity A to entity B, and also a blue polyline from entity A to entity B. I would like them not to overlap or blend, so I am imagining a fanning out as more lines are drawn, so that each line and what it represents can be visualized. I've included a crude drawing of what I'm trying to explain with the fanning out rather than overlapping.
I have a functional data structure keeping track of the lines I want to represent, as well as a Cesium map that they are already being programatically drawn on. I guess at this point I'm looking for the technical explanation of how to programatically bend the polylines on the map, and also any suggestions for polyline management in order to recognize overlapping lines so I can apply the bends.
Thanks for any help!
Here's one method. This sample code will "spread" the lines along longitude only, so works best on North/South lines and not on East/West lines. But I think it should convey the right idea, you just have to figure out a more general-purpose way of "moving" the midpoint to a visually pleasing location.
I'm using time-based paths here, to gain access to Cesium's interpolation logic. But I've selected a reference time far in the past, and I'm only showing the finished paths on the viewer. So, the user is none the wiser that time is playing any role here.
var viewer = new Cesium.Viewer('cesiumContainer', {
navigationInstructionsInitiallyVisible: false,
animation: false,
timeline: false,
// These next 5 lines are just to avoid the Bing Key error message.
imageryProvider : Cesium.createTileMapServiceImageryProvider({
url : Cesium.buildModuleUrl('Assets/Textures/NaturalEarthII')
}),
baseLayerPicker : false,
geocoder : false,
// This next line fixes another Stack Snippet error, you may omit
// this setting from production code as well.
infoBox : false
});
var numberOfArcs = 5;
var startLon = -105;
var startLat = 39.7;
var stopLon = -98.4;
var stopLat = 29.4;
var spread = 5;
var referenceTime = Cesium.JulianDate.fromIso8601('2001-01-01T00:00:00Z');
var midTime = Cesium.JulianDate.addSeconds(referenceTime, 43200, new Cesium.JulianDate());
var stopTime = Cesium.JulianDate.addSeconds(referenceTime, 86400, new Cesium.JulianDate());
for (var i = 0; i < numberOfArcs; ++i) {
var color = Cesium.Color.fromRandom({
alpha : 1.0
});
// Create a straight-line path.
var property = new Cesium.SampledPositionProperty();
var startPosition = Cesium.Cartesian3.fromDegrees(startLon, startLat, 0);
property.addSample(referenceTime, startPosition);
var stopPosition = Cesium.Cartesian3.fromDegrees(stopLon, stopLat, 0);
property.addSample(stopTime, stopPosition);
// Find the midpoint of the straight path, and move it.
var spreadAmount = (spread / (numberOfArcs - 1)) * i - (spread / 2);
var midPoint = Cesium.Cartographic.fromCartesian(property.getValue(midTime));
midPoint.longitude += Cesium.Math.toRadians(spreadAmount);
var midPosition = viewer.scene.globe.ellipsoid.cartographicToCartesian(
midPoint, new Cesium.Cartesian3());
// Redo the path to be the new arc.
property = new Cesium.SampledPositionProperty();
property.addSample(referenceTime, startPosition);
property.addSample(midTime, midPosition);
property.addSample(stopTime, stopPosition);
// Create an Entity to show the arc.
var arcEntity = viewer.entities.add({
position : property,
// This path shows the arc as a polyline.
path : {
resolution : 1200,
material : new Cesium.PolylineGlowMaterialProperty({
glowPower : 0.16,
color : color
}),
width : 10,
leadTime: 1e11,
trailTime: 1e11
}
});
// This is where it becomes a smooth path.
arcEntity.position.setInterpolationOptions({
interpolationDegree : 5,
interpolationAlgorithm : Cesium.LagrangePolynomialApproximation
});
}
// Optionally, add start and stop points, mostly for easy zoomTo().
viewer.entities.add({
position : Cesium.Cartesian3.fromDegrees(startLon, startLat),
point : {
pixelSize : 8,
color : Cesium.Color.WHITE
}
});
viewer.entities.add({
position : Cesium.Cartesian3.fromDegrees(stopLon, stopLat),
point : {
pixelSize : 8,
color : Cesium.Color.WHITE
}
});
viewer.zoomTo(viewer.entities);
html, body, #cesiumContainer {
width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden;
font-family: sans-serif;
}
<link href="http://cesiumjs.org/releases/1.30/Build/Cesium/Widgets/widgets.css"
rel="stylesheet"/>
<script src="http://cesiumjs.org/releases/1.30/Build/Cesium/Cesium.js">
</script>
<div id="cesiumContainer"></div>

Animate all SnakeAnimations at once instead of one - Leaflet js

Currently I am using Leaflet JS and an addon called "SnakeAnim" which can be found
here
All of my map markers before using the snake animation were loading together and drawing an arc from the markers starting position to a certain location all at once.
All of the markers end at this certain location for their arc.
My problem is when I use the SnakeIn() function that it only animates one marker at a time, what I want it to do is animate them all together, simultaneously.
Inside my PopulateMap function I have:
lg.addLayer(L.marker(latlng, { icon: cssIcon }));
lg.addLayer(L.Polyline.Arc([latlng.lat, latlng.lng],
[netLat, netLong],
{
color: "red",
vertices: 50,
weight: 1,
opacity: 1,
snakeSpeed: 50
}));
return lg;
Note! netLat + netLong always have the same values.
Once returned I add it to the map and call the snakeIn() function.
.addTo(map).snakeIn();
Using this code it produces one marker, draws an arc from the marker start location to the end location, then loads the next marker and repeats the process.
I tried doing this also and removed the .snakeIn() part from the end of .addTo(map):
lg.addLayer(L.marker(latlng, { icon: cssIcon }));
lg.addLayer(L.Polyline.Arc([latlng.lat, latlng.lng],
[netLat, netLong],
{
color: "red",
vertices: 50,
weight: 1,
opacity: 1,
snakeSpeed: 0
}).snakeIn());
This way did, in-fact load all of the markers at once, but also it loaded the arcs with no animation except for 1. The very last marker was the only one that would animate not the others.
So I'm wondering if anybody else has experienced this same problem and worked around it or if anybody has any ideas on how I would accomplish this.
Thanks for your help :)
For anybody with a similar problem, mine was related to adding them to lg.addLayer method.
What I do now is I add them to the map rather than the lg.layer:
function drawArc(source, destination, leafletMap) {
for (var i = 0; i < source.length; i++) {
L.Polyline.Arc([source[i].geometry.coordinates[1], source[i].geometry.coordinates[0]],
destination,
{
color: "red",
vertices: 200,
snakingSpeed: 200
})
.addTo(leafletMap).snakeIn();
}
}
This way, all of my lines start animating at the same time.

Best way to make marker resizable in leaflet

I am trying to resize my markers every time the map is zoomed in or out.
Currently I am using this approach:
Iterate all markers in zoomend method.
get current icon size
Perform some calculation to get the new marker size according the zoom size.
set the new dimension to the icon object.
map.on('zoomend', function() {
zoomEndLevel = map.getZoom();
var difference = zoomEndLevel - zoomStartLevel;
console.log("difference in zoom " + difference);
markerArray.forEach(function(marker) {
var icon = marker.options.icon;
var oldX = icon.options.iconSize[0];
var oldY = icon.options.iconSize[1];
var newX = getNewIconAxis(oldX, difference);
var newY = getNewIconAxis(oldY, difference);
console.log(newX + " " + newY);
icon.options.iconSize = [ newX, newY ];
marker.setIcon(icon);
});
});
map.on('zoomstart', function() {
zoomStartLevel = map.getZoom();
});
function getNewIconAxis(value, zoomChange) {
if (zoomChange > 0) {
for (var i = zoomChange; i > 0; i--) {
value = value * 2;
}
} else {
for (var i = zoomChange; i < 0; i++) {
value = value / 2;
}
}
return value;
}
Problem :
This code works fine if I zoom in and out 1 level at once. If I scroll in and out my mouse too frequently then this code given strange outputs. Sometimes the marker size becomes too large or too small.
Question :
1) Is this the only way to make the markers resizable on different zoom levels?
2) If yes then what am I missing here or what changes should be made to make it work perfectly.?
Note : Tagging google maps also because it's more of a logical issue with map (either google or leaflet or mapbox) rather than api specific issue.
Looks like there are several previous posts that you guide you:
Mapbox,leaflet: Increase marker size on Zoom
is there a way to resize marker icons depending on zoom level in leaflet?
https://gis.stackexchange.com/questions/171609/resize-divicons-svgs-at-zoom-levels-leaflet
As for your bug, instead of reading the current icon size value at "zoomstart" event, you might better remember the previous zoom value and read it only at "zoomend" event. I am not sure the "zoomstart" event is fired only once when you scroll (to zoom in/out) successively, while the "zoomend" event may be fired only at the very end.

How to dynamically move Vector Features in OpenLayers 3

Based from an example given here: http://openlayers.org/en/vector-api/examples/dynamic-data.html?q=dynamic
Instead of using circle:
var imageStyle = new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({color: 'yellow'}),
stroke: new ol.style.Stroke({color: 'red', width: 1})
});
I want to use Vector Feature (Marker) as the object which is moving instead of using that yellow circle.
An example of using a feature vector is found here:
how to add markers with OpenLayers 3
Sorry, just a beginner in OpenLayers 3. Hope someone can help me. Thanks!
I've made you a basic example.
The idea is: You move an Overlay through a path using an interval to change its position like:
//fire the animation
map.once('postcompose', function(event) {
interval = setInterval(animation, 500);
});
var i = 0, interval;
var animation = function(){
if(i == path.length){
i = 0;
}
marker.setPosition(path[i]);
i++;
};

Categories