Hello!
I’m trying to create custom icon for each marker on data from geoJson file with supercluster.
I took a look at the Leaflet reference but I didn’t find a solution.
Can you please help me out or get me some references?
Thanks!
Hello!
I’m trying to create custom icon for each marker on data from geoJson file with supercluster.
I took a look at the Leaflet reference but I didn’t find a solution.
Can you please help me out or get me some references?
Thanks!
Could you elaborate? How many icons do you have?
Hi Emil,
It’s About 83 icons.
Assumig the icons are hosted (or alternatively, you put them in your assets folder), you can do it like this,
import dash_html_components as html
import dash_leaflet as dl
import dash_leaflet.express as dlx
from dash import Dash
from dash_extensions.javascript import assign
# A few countries.
countries = [dict(name="Denmark", iso2="dk", lat=56.26392, lon=9.501785),
dict(name="Sweden", iso2="se", lat=59.334591, lon=18.063240),
dict(name="Norway", iso2="no", lat=59.911491, lon=9.501785)]
# Generate geojson with a marker for each country and name as tooltip.
geojson = dlx.dicts_to_geojson([{**c, **dict(tooltip=c['name'])} for c in countries])
# Create javascript function that draws a marker with a custom icon, in this case a flag hosted by flagcdn.
draw_flag = assign("""function(feature, latlng){
const flag = L.icon({iconUrl: `https://flagcdn.com/64x48/${feature.properties.iso2}.png`, iconSize: [64, 48]});
return L.marker(latlng, {icon: flag});
}""")
# Create example app.
app = Dash()
app.layout = html.Div([
dl.Map(children=[
dl.TileLayer(), dl.GeoJSON(data=geojson, options=dict(pointToLayer=draw_flag), zoomToBounds=True)
], style={'width': '100%', 'height': '50vh', 'margin': "auto", "display": "block"}, id="map"),
])
if __name__ == '__main__':
app.run_server()
thanks for the timely response
I have just updates the documentation with more GeoJSON
examples, including the custom-icon one
That’s awesome!!
I seem to get the error:
No match for [dashExtensions.default.function0] in the global window object.
When attempting this example when providing the page content via a callback. It seems like the assign function isn’t being created/found somehow. Any thoughts on how to work around this?
My guess is that you are trying to assign javascript functions dynamically. You should define all javascipt functions before starting the app (similar to callbacks). But if you post an MWE, I can take a closer look
Thank you Emil,
That was essentially the issue. I’m deploying the app on PCF so the function is not writeable at the time of assignment. Your prompt was enough for me to alter the example by:
window.dashExtensions = Object.assign({}, window.dashExtensions, {
dashExtensionssub: {
draw_icon: function(feature, latlng) {
const flag = L.icon({
iconUrl: `xxx.png`,
iconSize: [64, 48]
});
return L.marker(latlng, {
icon: flag
});
},
}
});
ns = Namespace('dashExtensions','dashExtensionssub')
marker_out = dl.GeoJSON(data=geojson, options=dict(pointToLayer=ns('draw_icon')))
Yes, that will work as well. Behind that scenes, that’s what the Python code is in fact doing; writing the JS functions to the assets folder, and mapping name spaces and variable names accordingly
I’m getting this error when the app is deployed on heroku. Locally it works just fine. I have been trying different methods for hours and I’m out of ideas at this point. What am I missing?
Here is the dashExtensions_default.js file:
window.dashExtensions = Object.assign({}, window.dashExtensions, {
default: {
function0: function(feature, latlng, context) {
const {
min,
max,
colorscale,
circleOptions,
colorProp
} = context.props.hideout;
const csc = chroma.scale(colorscale).domain([min, max]);
circleOptions.fillColor = csc(feature.properties[colorProp]);
return L.circleMarker(latlng, circleOptions);
},
function1: function(feature, latlng) {
const pictogram = L.icon({
iconUrl: `/assets/${feature.properties.category}.png`,
iconSize: [24, 24]
});
return L.marker(latlng, {
icon: pictogram
});
}
}
});
and this is the python code for the map
ns = Namespace("dashExtensions", "default")
dl.Map(
children=[
dl.TileLayer(
url="https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>',
id="base_map",
maxZoom=20,
),
dl.Pane(
id="points_pane",
children=[
dl.GeoJSON(
data={},
zoomToBounds=True,
id="points",
format="geobuf",
hoverStyle=arrow_function(
dict(weight=3, color="#16E2F5", dashArray="")
),
options=dict(pointToLayer=ns("function0")),
)
],
style={"z-index": 1000001},
),
dl.Pane(
id="markers_pane",
children=[
dl.GeoJSON(
data={},
id="markers",
format="geobuf",
options=dict(pointToLayer=ns("function1")),
)
],
style={"z-index": 3},
),
],
center=[0,0],
zoom=8,
id="map",
style={
"width": "100vw",
"height": "100vh",
"z-index": "0",
"position": "relative",
},
),
Could it be that the path to the assets folder is not set correctly? In another part of the application I’m showing some images that are stored in the assets folder and those also don’t show up.
Is Namespace
imported from dash_extensions.javascript
here?