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;
}
Related
var rectangle = new Graphics();
rectangle.beginFill(0, 0.001);
rectangle.lineStyle(1, 0xFF0000);
rectangle.drawRect(5, 5, 200, 100);
rectangle.interactive = true;
rectangle.buttonMode = true;
rectangle.on('pointerdown', onDragStart)
.on('pointerup', onDragEnd)
.on('pointerupoutside', onDragEnd)
.on('pointermove', onDragMove);
app.viewport.addChild(rectangle);
I'm using this code to create a rectangle and adding it to rectangle. This is the onDragMove Function
function onDragMove() {
if (this.dragging) {
const newPosition = this.data.getLocalPosition(this.parent);
this.width = newPosition.x;
this.height = newPosition.y;
}
}
This is basically changing its width and height, but I also want to Drag the Rectangle when clicked inside the rectangle and dragged on the screen. Any suggestions how can I achieve this?
Borders to change width/height
clicking inside rectangle to drag on the screen.
I created working example of dragging and resizing: https://www.pixiplayground.com/#/edit/SbpTjm7WKXbL51kmiG89W - please check.
when you click near bottom border of rectangle (+/- 20 px) then you will start resizing it.
when you click in any other place inside rectangle then you will drag it
Basing on this example i think you can implement resizing of other borders of rectangle etc :)
One note: please look at function drawRectangle :
function drawRectangle(rectangle)
{
rectangle.clear();
rectangle.beginFill(0, 0.001);
rectangle.lineStyle(1, 0xFF0000);
rectangle.drawRect(rectangle.myRectanglePosition[0], rectangle.myRectanglePosition[1], rectangle.myRectanglePosition[2], rectangle.myRectanglePosition[3]);
}
^ the rectangle.clear(); is called to redraw the PIXI.Graphics object. So on each frame we clear and draw it again on specific position with specific width & height.
I need to develop 2 animations on a polygon:
automatic rotation of each segments
the polygon follows the mouse movements
I'm trying to do that with this code:
// onMouseMove
tool.onMouseMove = function (event) {
mousePoint = event.point;
};
// onFrame
view.onFrame = function (event) {
// Animation 1: Automatic circular rotation of each segment
for (var i = 0; i < polygon.segments.length; i++) {
var offsetRotation = new Point(Math.cos(event.time + i * 2), Math.sin(event.time + i * 2)).multiply(10);
polygon.segments[i].point = polygonCached.segments[i].point.add(offsetRotation);
}
// Animation 2: the polygon moves following the mouse movements with transition
var delta = mousePoint.subtract(polygon.position).divide(15);
polygon.position = polygon.position.add(delta);
};
Here is the whole code: https://codepen.io/anon/pen/YMgEEe?editors=0010
With the above code the automatic rotation of each segments works and the polygon doesn't follow the mouse at all and also without the transition.
Instead, commenting the automatic rotation animation it correctly follows the mouse with transition.
To check if transition works I move the mouse cursor outside of browser window and then go back from another point. Now you'll see no transition when the polygon moves.
Where I'm wrong?
Just move the polygonCached as well.
polygonCached.position = polygonCached.position.add(delta);
https://codepen.io/arthursw/pen/LvKPXo
The cached version of the polygon was not moving, so each time you rotated your points, their position was reset.
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>
I'm using a some code from https://github.com/dimxasnewfrozen/Panning-Zooming-Canvas-Demos/blob/master/demo12/main.js (demo at http://dayobject.me/canvas/demo12/) to zoom in on an image using the Canvas element.
However, when zooming the jump between one zoom level and the next is too large, so I need to add a scale parameter.
How would I got about doing this?
In your main.js, you can change your zoomLevel here,
mouseWheel: function (e) {
e.preventDefault() // Please add this, coz the scroll event bubbles up to document.
var zoomLevel = 2;
...
if (delta > 0)
{
// ZOOMING IN
var zoomedX = canvasPos.deltaX - (canvasZoomX - canvasPos.deltaX);
var zoomedY = canvasPos.deltaY - (canvasZoomY - canvasPos.deltaY);
// scale the image up by 2
initialImageWidth = initialImageWidth * zoomLevel;
}
else
{
// ZOOMING OUT
var zoomedX = (canvasPos.deltaX + canvasZoomX);
var zoomedY = (canvasPos.deltaY + canvasZoomY);
// scale the image down by 2
initialImageWidth = initialImageWidth / zoomLevel;
}
}
Disclaimer: this ruins the zoomedX and zoomedY values. You gotta fix them :)
It seams to me as if the algorithm always takes half of the dimension befor the zoom. At the end of you code you see it in main.js the mouseWheel function:
initialImageWidth = initialImageWidth * 2;
the width is divided by 2 so just change the used value.
You said the step used to zoom in and out is too big.
So I suggest that you generate the new value by using the dimensions of the image you want to zoom. For example you take a percentage of the biggest dimension of the current image.
That's how you can implement a zoom function that zooms according to the dimensions of the image
I'm building a cesium app and I need my points to indicate a rotational heading. I'm using billboards to display an image I created to show this heading; however, when I rotate the globe, the points don't rotate with it, making the heading indicators incorrect.
In other words, the rotation of my billboards stay constant with the screen space, but not with the globe.
Here's an aerial view of New York. The points in question are in the lower left corner of the image. Note that the heading indicators are pointing northeast.
Here's the same view, but rotated 180° so that up is South. Now, the heading indicators are still pointing to the northwest of the screen, but I need it to be pointing to the globe's northeast, i.e. towards Manhattan.
Here's the code that displays a point:
var entity = {
id: data.cluster_number + '_' + point.id,
name: point.id,
position: Cesium.Cartesian3.fromDegrees(point.lon, point.lat),
billboard: {
image: 'assets/img/point.png',
color: color,
rotation: -1 * toRadians(point.heading),
scale: point.size * 0.07
}
};
if (!angular.isDefined(viewer.entities.getById(entity.id))) {
viewer.entities.add(entity);
}
What's the easiest/most effective way to get the points to rotate with the globe/map?
You need to do a few things.
1 - Update the rotation property of the billboard to be a CesiumCallbackProperty.
rotation: new Cesium.CallbackProperty(
function () {
return -1 * toRadians(point.heading);
}, false);
2 - You'll need to update the heading property of the point based on the camera's heading.
point.heading = viewer.camera.heading;
3 - You'll want to update that point on an interval, either using the cesium clock:
mapContext.clock.onTick.addEventListener(function() {...});
or using JavaScripts setInterval
Once all that is set up here is how it works.
The billboard on the map continuosly pulls the rotation from the point, and if it changes, it will update the billboard on the map. Each time the interval or clock ticks, the value being used changes, based on the heading of the camera.
NOTE: The heading property on the camera is in radians.
Set the billboard's alignedAxis to Cesium.Cartesian3.UNIT_Z instead of the default screen up vector. Run following sample in SandCastle to demonstrate that it works:
var viewer = new Cesium.Viewer('cesiumContainer');
var position = Cesium.Cartesian3.fromDegrees(-111.572177, 40.582083);
var cesiumTerrainProviderMeshes = new Cesium.CesiumTerrainProvider(
{ url : '//assets.agi.com/stk-terrain/world' }
);
//viewer.terrainProvider = cesiumTerrainProviderMeshes;
//viewer.scene.globe.depthTestAgainstTerrain = true;
var ellipsoid = viewer.scene.globe.ellipsoid;
var billboardCollection = viewer.scene.primitives.add(new Cesium.BillboardCollection(
{ scene : viewer.scene }
));
billboardCollection.add(
{ position : position, image : '../images/facility.gif', //heightReference : Cesium.HeightReference.CLAMP_TO_GROUND, rotation: Cesium.Math.PI/4, alignedAxis : Cesium.Cartesian3.UNIT_Z }
);