Change Icon of Single Vector Feature in Layer - javascript

Currently I am trying to change the icon of a particular feature of a vector layer that the user is focusing on. I add each feature to the map like so:
var point = new OpenLayers.Geometry.Point(pt.lon, pt.lat);
var markerStyle = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {
externalGraphic: iconURL
});
var marker = new OpenLayers.Feature.Vector(point, attributes, markerStyle);
Later I do the following to update the feature's icon:
var marker = this.findSelectedMarker();
if (marker) {
marker.style.externalGraphic = newIconUrl;
this.layer.redraw();
}
But when the layer redraws, all features in my layer use the newIconUrl, not simply the selected marker that I am trying to update.
How can I change the icon of the one selected feature of my layer? Thanks.

There were two issues I needed to fix in order to solve this. The first was related to using multiple OpenLayers styles, both at the layer level as well as the individual feature level. I removed the styling for each individual feature, so that only the following layer style was being implemented:
this.layerStyle = new OpenLayers.StyleMap({
'default': {
externalGraphic: media_url + '${iconURL}',
graphicHeight: 32,
graphicWidth: 32,
graphicXOffset: -16,
graphicYOffset: -32,
fillOpacity: 0.75
}
});
The second change I made was to use attribute replacement syntax to designate the icon URL with a feature attribute called '${iconURL}'. This allowed me to change the icon url by simply changing an attribute of the selected feature and redraw the layer:
focusedMarker.attributes.iconURL = this.focusedURL;
this.layer.redraw();

Related

Highlight custom icons in Leaflet

I'm using markers with custom images in Leaflet, like this:
// A template for icons when they get instantiated on the map
var UnitIcon = L.Icon.extend({
options: {
iconSize: [40, 40],
iconAnchor: [20, 35]
}
});
function PlaceIconOnMapAtLatLng(iconURL, lat, lng)
{
var newIcon = new UnitIcon({iconUrl: iconURL});
var myMarker = L.marker([lat, lng], {icon: newIcon, draggable: true}).addTo(map);
}
The custom images sit in a folder and get read at run-time. The idea is that the user can change these and have as many as they want.
My problem is that when it comes to highlighting these, e.g. on click, there doesn't seem to be any straightforward way to do this in Leaflet. Initially I thought about just drawing a shape around the icon, but then this would be treated as its own separate thing that would be dragged around separately, whereas I want it to stay with its associated icon at all times.
A horrible first attempt would be something like having an update running constantly that sets the position of the highlight to whatever the selected marker's position is.
Or is there some way to associate objects e.g. as "children" so that when their parent object moves, the child moves with it?
I would preferably like an explicit highlight instead of doing something like changing the size or opacity of the selected marker, or giving it a pop-up, although these could be fall-back options. The reason I want a highlight is because ultimately I want to be able to highlight multiple icons at once, and having loads of pop-ups etc. doesn't seem like a very nice way of doing that.
You can add a CSS-Class to the Icon.
marker.on('click', function (e){
var layer = e.target;
if(!L.DomUtil.hasClass(layer._icon, 'dash-border')){
L.DomUtil.addClass(layer._icon,'dash-border');
}else{
L.DomUtil.removeClass(layer._icon,'dash-border');
}
});
.dash-border {
border: 2px dashed #3388ff;
background-color: #3388ff4d;
}
https://jsfiddle.net/falkedesign/r9onevq2/

Is there a way to apply a CSS class to an Openlayers 5.3 feature?

We have over 2000 map points to draw in an openlayers (5.3.2) map. Performance is a big issue as we are:
creating a vector layer,
adding a feature per point (for location of tooltip),
adding an overlay per point (for material icon with css class "blink_me" applied depending on a flag per point),
adding a single overlay on mouse hover to show a tooltip dynamically filled in with whatever data is specific to the feature that's detected on that hover location.
To reduce performance issues, I've already moved the style of the feature out to the vector layer but I also want to remove the overlays for each point (not the tooltip one) and move the map icon to the feature. Only problem is that there seems to be no way to apply a css class to a feature object even though it can hold an HTMLImageElement.
It looks like you used to be able to set className on imageDiv back in openlayers 2 (OpenLayers: Adding a (css-)class to a marker?) so something like that would be perfect.
// map pin that used to be set on overlay
const divelement = document.createElement('i');
divelement.classList.add('material-icons', 'text-outline');
if (paramFlagIsTrue) {
// only add the blinking class if param of the
// function where this code sits is true.
divelement.classList.add('blink_me');
}
divelement.innerHTML = 'place';
divelement.style.fontSize = '32px';
divelement.style.width = '32px';
divelement.style.height = '32px';
divelement.style.color = paramColor;
// feature containing location, styles etc
const pointFeature = new Feature({
name: 'myFeature',
geometry: point,
index: paramIndex
});
// Feature style without that "blink_me" class added and using an image, rather than a material icon font letter.
// I'd look at moving the feature style back to the actual feature away from the vector layer like so if I can set a class on each feature style according to a flag.
pointFeature.setStyle(
new Style({
image: new Icon(/** #type {module:ol/style/Icon~Options} */{
anchor: [0.5, 0.96],
color: element[3],
crossOrigin: 'anonymous',
src: 'assets/outline_place_black_18dp.png'
})
})
);
this.multiPointSource.addFeature(pointFeature);
...

Google Maps API v3, Remove Marker icon or changing to "null"?

I'm writing a Python Flask application in which I'm using Google Maps. I want to be able to add labels to a polyline that I've drawn which symbolizes a ship route.
The route is drawn using a set of coordinates and the polyline feature of the Maps API. I want to add time labels to the polyline and the easiest way seems to be to use Map Markers. However I don't want the large standard pins to show up, but would prefer a small icon/marker together with my text or even none at all. As far as I have gathered you can create "Circles" (which are modifiable) or "Markers" (which you only can change the icon of). I would prefer to go with "Circles", but those you apparently can't add text to..
How can I add text to my map and avoid the Google Maps Pins showing up?
Currently I have an list of objects that contains latitude, longitude and date + time. I'm iterating through it adding markers, but as I do I would like to keep out the marker icon or instead draw the circles if someone knows how to draw circles with added text?
for(i = 0; i < markerList.length; i++){
var position = new google.maps.LatLng(markerList[i].lat, markerList[i].lng);
var date = markerList[i].date;
var marker = new google.maps.Marker({
position: position,
label: date,
map: map,
icon: "None" //Produces error: 404 (NOT FOUND)
});
}
Being able to change the label size also is a very much appreciated function, but I have been unable to find any information about whether that is available. Being able to change the color of the text would also be nice.
As no answers have been given yet and I've sort of found a solution to my problem I guess I will share for others out there with the same problem. At least until someone comes up with a better solution:
I ended up using a predefined symbol and scaling it down to 0 in size as follows:
for(i = 0; i < markerList.length; i++){
var position = new google.maps.LatLng(markerList[i].lat, markerList[i].lng);
var date = markerList[i].date;
var marker = new google.maps.Marker({
position: position,
label: date,
map: map,
icon: {
path: google.maps.SymbolPath.CIRCLE,
scale: 0
}
});
}
Sadly I haven't found a way to mess with the label yet.
try markerWithlabel and you can change the icon of the marker whit a svg or png plus the label too
like this jsfiddel
.
#Zeliax You can add visible: false to not have marker icon show on your google map. icon prop looks for a path that you want specify for your marker to look as. It is basically a url for your display image.

How to dynamically adjust zoom in Heatmap.js in OpenLayers

Consider the following code:
heatmap = new OpenLayers.Layer.Heatmap( "Heatmap Layer", map, osm,
{visible: true, radius: radiusForScale[zoom], legend: {position: 'br',title: 'title'}},
{isBaseLayer: false, opacity: 0.3, projection: new OpenLayers.Projection("EPSG:4326")}
);
Background: heatmap.js is great for displaying population densities and such... however, I do not want heatmap.js to control the radius of my points. Instead, I wish to dynamically updated the radius based on a custom zoom function I have created, without having to destroy the heatmap and recreate it every time the zoom changes. Now, this is possible if you add the heatmap to a div as follows:
var config = {
element: document.getElementById("heatmapArea"),
radius: 30,
opacity: 50
};
//creates and initializes the heatmap
var heatmap = h337.create(config);
In this example, it's as simple as updating the JSON object and updating the display. However, this in only a static display assigned to a div, and therefore renders the vector layer useless. Has anyone had any success with this in OpenLayers??
On a side note: I've browsed through all the keys in the heatmap JSON string and there doesn't seem to be a way to change the zoom variable.
Figured it out... this isn't advertised in the documentation or anywhere on the internet that I could find.. however, here's how you control the radius in OpenLayers for those of you who need it. Let's keep it simple..
// create our heatmap layer
var heatmap = new OpenLayers.Layer.Heatmap(
"Heatmap Layer", map, osm, {visible: true, radius:50},
{isBaseLayer: false, opacity: 0.3, projection: new OpenLayers.Projection("EPSG:4326")}
);
map.addLayers([heatmap]);
Now add the data:
heatmap.setDataSet(data);
Here's the key. You can do pretty much anything with this list of commands:
this.set("radius",value); //****this one solved my problem
this.set("element",value);
this.set("visible",value); //deceiving! You have to access the canvas subclass to get it to work
this.set("max",value);
this.set("gradient",value);
this.set("opacity",value);
this.set("width",value);
this.set("height",value);
this.set("debug",value);
So, for example, create a zoom event so the radius changes based on your radius function. For me, it was as simple as scaling the radius based on the ratio screen width(pixels)/screen width(meters). So now in your click event:
on zoom change: //pseudocode
canvas = heatmap.heatmap.get('canvas'); //this is the subclass I spoke of above
if the zoom is above a certain value //pseudocode
then
canvas.style.display = 'block'; //show the heatmap... you can also use heatmap.toggle() but this gives you more control
heatmap.heatmap.set('radius',zoomfunction[map.zoom]); //this dynamically updates the radius!!
heatmap.updateLayer();
else
canvas.style.display = 'none';
heatmap.updateLayer();
I hope this helps someone 'cause it drove me crazy!

How do I programatically change layers in Leaflet?

I don't want to the show the layers control on the map, but I want to put some buttons somewhere else to change between layers. Is this possible to change the layer programmatically?
Suppose you have a map:
var map = L.map('worldmap-map').setView([37.8, -96], 4);
To remove a layer, layer1:
map.removeLayer(layer1)
To remove a control layer, ctrlLayer,
map.removeControl(ctrlLayer)
Or you want to add a layer1 to map:
layer1.addTo(map)
For an example, there is a Leaflet example : http://leafletjs.com/examples/choropleth-example.html
You could use firebug or chrome dev tools to see its source.
From https://stackoverflow.com/a/33762133/4355695 : Just myTileLayer.addTo(map) does the job of changing background layer (without adding on top), if it is already part of the base layers. And you don't need to explicitly remove the previously selected background layer.

Categories

Resources