Having trouble combining hover state and click to zoom capability (fitToBounds?) - javascript

Extreme beginner here. I found this (https://www.mapbox.com/mapbox-gl-js/example/hover-styles/) tutorial that does the first part of what I'm trying to do (hover effect on US States) but I would like to add the ability to click on a state and have the map zoom to the bounds of that state.
Basically looking to do something like this https://leafletjs.com/examples/choropleth/ but in mapbox gl.
Many thanks, even if only pointing out where I should start.

You can use map.on('click', <layer-name> ... to set up your click listener. This example should help you with the structure: https://www.mapbox.com/mapbox-gl-js/example/polygon-popup-on-click/
In order to properly use fitBounds within the listener, you'll need to "convert" the raw polygon coordinates to a mapgoxgl.LngLatBounds object. This example does it for a LineString (but the approach can be adapted to work with a polygon): https://www.mapbox.com/mapbox-gl-js/example/zoomto-linestring/
Without knowing the names of your layers, I can recommend something that looks roughly like the following:
map.on('click', 'state-fills', function(e) {
var coordinates = e.features[0].geometry.coordinates[0];
var bounds = coordinates.reduce(function(bounds, coord) {
return bounds.extend(coord);
}, new mapboxgl.LngLatBounds(coordinates[0], coordinates[0]));
map.fitBounds(bounds, {
padding: 20
});
});

Related

Add vertex to Leaflet polyline programmatically

I'm using Leaflet and Leaflet PM and their polyline tool to create a polyline. Everything works fine when clicking and adding new points to the map. This data I then use to store away somewhere else and do some other stuff with it. The thing is.
I am going to have a function to be able to press the 'e' key and 'd' key to add points to the map using DOM Eventlisteners. This is because I need to change floor elevation. And if I use the mouse for that on the same location as a previously added point it closes the polyline. Also there it works great. I use mouseover on the map, store the lat long, and then on keydown I use my workingLayer to addLatLng(latlng). It saves the latitudes and longitudes, it draws the line. But there are no vertexes added as when I'm clicking. And I need the vertexadded function to be able to add my other meta-data to it. I'm also gonna use those vertexes to customize later on.
I've been spending the whole day on this and I really need some help now, can't find anything about it.
I also tried adding a marker directly to the layer but that didn't work.
All in all. Everything works fine when I'm clicking to make the polyline. But when programmatically call the layer.addLatLng(latlng); won't add the vertex. Only the latlng and where it is, as shown in the images. Therefore pm:vertexadded is never called.
What am I missing?
An example from my code:
lmap.on('pm:drawstart', function(e){
//Layer is now the workingLayer
let layer = e.workingLayer;
//Will hold coordinates from map
let pointFromMouse;
lmap.addEventListener('mousemove', function(e){
//Assigning current position lat/long
pointFromMouse = e.latlng;
})
document.addEventListener('keydown', function(e){
if(e.keyCode == '69'){
//When pressing 'e', adds it to the polyline
layer.addLatLng(pointFromMouse);
//I also tried setLatLngs(); and redraw(); no sucess
}
})
layer.on('pm:vertexadded', function(e){
//Here I'm calling some other stuff. I stuff another array along
//with other meta-data, other than lat/long.
})
})
Image1: How it looks when I'm clicking(Everything works fine, vertexes are added).
Image2: How it looks when I'm adding a point pressing the key. No vertextes are added, Therefore pm:vertexadded is never called.

How to mimic leaflet default panel buttons

I am working on a leaflet application and would like to mimic the default draw control panel buttons to move them to a more convient location on my application. The icons in question being these
I can see the objects within the drawcontrol I just don't know how to invoke these methods
Thanks so much
I found the solution, the primary call looks like so
this.polyline.enable(); for the draw functions, meaning that marker would look like
this.marker.enable();
defined as
this.polyline = new L.Draw.Polyline(this.map, { shapeOptions: { color: 'green' } });
this.marker = new L.Draw.Marker(this.map, {icon: new mark()});
same goes with the other polys to add to the map, zoom-in/out is also this.map.zoomIn; this.map.zoomOut respectively

Is there a way to change the layout/style when a user zooms in a plotly line chart?

The documentation for plotly is a bit hard to use and couldn't find a specific settings for relayout on zoom.
The method I used is to add a 'plotly_relayout' event listener and then check the event data if it has 'xaxis.range[0]'. If it does then I make some update and then do a relayout and restyle.
var gd = document.getElementById(chart_id);
gd.on('plotly_relayout', function (eventdata) {
// Check if a pan or zoom occurred.
if (eventdata.hasOwnProperty('xaxis.range[0]')) {
layout_update = {...,...};
trace_update = {...,...};
Drupal.plotly.relayout(chart_id, layout_update);
Drupal.plotly.restyle(chart_id, trace_update);
}
}
This might be an inefficient way of going about it, though. It seems to be a bit slow. Also it cannot differentiate between a pan and a zoom action as the event data is the same. Is there a better way?

HTML Link to a Leaflet / Mapbox marker

I use Mapbox for a dynamic map on a website. It works really well except, I have a sidebar which list the pins with a little more description and an image. I want to make it so when I click on that sidebar, it would fire the click event of that marker on the map.
I used to do this all the time with Google Maps but now I'm stuck because even in the case that I can keep the instance of the marker, I cannot fire the click on it for some reason. It simply does nothing (maybe I need to re-bind the click event on it but I don't know how with mapbox)
I've encountered a few questions about this on Google and SO but none bring a real answer to that question except "keep the instance" which isn't always possible in some cases.
So basically I have a jQuery click event like this:
var marker = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [lng, lat]
},
properties: {}
};
if (isPin) {
marker.properties = pinStyles.pin;
} else if (isWinery) {
marker.properties = pinStyles.winery;
} else {
marker.properties = pinStyles.user;
}
marker.properties.title = locationName;
marker.properties.description = pin.description;
var markerObject = L.mapbox.markerLayer(marker);
// Add to cluster
markers.addLayer(markerObject);
$('#marker_list a.marker_item:last').click(function() {
var geoJson = markerObject.getGeoJSON();
markerObject.fire('click'); // does nothing (openPopup makes "Uncaught TypeError: Object [object Object] has no method 'openPopup' " so I guess I'm not doing it right)
});
And I have this (click event for mapbox marker):
map.markerLayer.on('click', function(e) {
map.setView(e.layer.getLatLng(), map.getZoom());
});
Anyone has an idea about wether 1) fix the non-firing event OR 2) make an HTML link fire a mapbox marker click event OR .openPopup?
Thanks and have a nice day!
MapBox's marker layer is a collection of Leaflet markers. You can create an href to a function that look for a particular marker based on it's layer id.
map.markerLayer.getLayers() returns an array of layer objects that contain both a _leaflet_id and the method togglePopup.
Try matching your href call to the leaflet id and then fire map.markerLayer.getLayers()[i].togglePopup()
Let me know if this helps.

Customize OpenLayers Control

How can I easily customize OpenLayers map controls? Or at least, how can I minimize the controls' height?
Thank you.
PS. Is there any CSS override?
You can sub-class any of the openLayers controls. I just made a 'zoom-slider' by sub-classing PanZoomBar (panZoomBar.js), overriding the draw() method and commenting out all the button elements, just leaving the zoom slider.. like this:
function zoomSlider(options) {
this.control = new OpenLayers.Control.PanZoomBar(options);
OpenLayers.Util.extend(this.control,{
draw: function(px) {
// initialize our internal div
OpenLayers.Control.prototype.draw.apply(this, arguments);
px = this.position.clone();
// place the controls
this.buttons = [];
var sz = new OpenLayers.Size(18,18);
var centered = new OpenLayers.Pixel(px.x+sz.w/2, px.y);
this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, 5), sz);
centered = this._addZoomBar(centered.add(0, sz.h + 5));
this._addButton("zoomout", "zoom-minus-mini.png", centered, sz);
return this.div;
}
});
return this.control;
}
var panel = new OpenLayers.Control.Panel();
panel.addControls([
new zoomSlider({zoomStopHeight:11}),
new OpenLayers.Control.LayerSwitcher({'ascending':false}),
]);
map.addControl(panel);
There is a CSS file that comes with can controls all of the CSS commands for within openlayers generally .olZoombar { here}
It is probably the easiest way to edit those sorts of things otherwise you can edit the actual .js file for the control.
If you are talking about the PanZoomBar or ZoomBar, as has been mentioned, you need to edit the zoomStopHeight. However, You do not need to edit OpenLayers.js.
new OpenLayers.Control.PanZoomBar({zoomStopHeight: 7})
You could consider trying PanZoom, which has no bar.
To minimize the ZoomBar search for zoomStopHeight in OpenLayers.js and edit it as you wish.
Further reference: Link.
Take a look here - http://geojavaflex.blogspot.com/
I am in the process of showing how to do an involved customization of the LayerSwitcher. This might give you ideas on how to do what you are after.
There is a map on the page that shows how the control works, and subsequent posts will discuss the code in detail.
If you are just interested in code see the source of the page and look for the link to CustomLayerSwitcher.js for the customized version of the switcher.

Categories