Hi All,
When I have a map with different PointFeatures I would like to display a text ( tooltip ) if the mouse moves over the PointFeature. Any idea how to realise this ?
Regards
Felix
Hi All,
When I have a map with different PointFeatures I would like to display a text ( tooltip ) if the mouse moves over the PointFeature. Any idea how to realise this ?
Regards
Felix
Greetings,
Right now, there is no out of the box solution for “tooltip”. But we have an issue that should implement it. Do you need solution like this?
Below click event, not mouse over
Best regards,
Dmitry
Hi @d.cherkasov
This issue would be the solution. If there are a lot of points and by hovering over you find the point to click on it, would be perfect.
Best regards
Felix
Okay, then I will back later with temporary solution before the ticket would be implemented
Hello again,
I did temporary solution that will show “tiptools” when user clicks on Points (or whatever you need).
Basically, this is JS executed code + a bit html:
Screen:
package com.company.jmixmapstest.view.mappoint;
import com.company.jmixmapstest.view.main.MainView;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.router.Route;
import io.jmix.flowui.Notifications;
import io.jmix.flowui.view.*;
import io.jmix.mapsflowui.component.GeoMap;
import io.jmix.mapsflowui.component.model.feature.MarkerFeature;
import io.jmix.mapsflowui.component.model.source.DataVectorSource;
import io.jmix.mapsflowui.component.model.source.SourceFeatureClickNotifier;
import io.jmix.mapsflowui.component.model.source.VectorSource;
import org.locationtech.jts.geom.Point;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static io.jmix.maps.utils.GeometryUtils.createPoint;
@Route(value = "map-points", layout = MainView.class)
@ViewController(id = "MapPoint.view")
@ViewDescriptor(path = "map-point-view.xml")
@CssImport("./styles/ol-popup.css")
public class MapPointView extends StandardView {
@ViewComponent("map.dataVectorLayer.buildingSource")
private DataVectorSource<Object> buildingSource;
@ViewComponent("map.vectorLayer.vectorSource")
private VectorSource vectorSource;
@ViewComponent("map")
private GeoMap map;
@ViewComponent("popup")
private Div popup;
@ViewComponent("popupContent")
private Div popupContent;
@ViewComponent("popupCloser")
private com.vaadin.flow.component.button.Button popupCloser;
@Autowired
private Notifications notifications;
private Map<String, String> markerDescriptions = new HashMap<>();
@Subscribe
public void onBeforeShow(final BeforeShowEvent event) {
// Initialize marker descriptions
markerDescriptions.put("POINT (30.327877976068475 59.94327979807139)", "Saint Petersburg, Russia");
markerDescriptions.put("POINT (13.722223426393388 51.05181869560283)", "Dresden, Germany");
markerDescriptions.put("POINT (-2.2449710026111562 53.47839876123808)", "Manchester, UK");
// Add click listener
vectorSource.addSourceFeatureClickListener(this::onVectorSourceClick);
// Add markers
vectorSource.addAllFeatures(List.of(
new MarkerFeature(createPoint(30.327877976068475, 59.94327979807139)),
new MarkerFeature(createPoint(13.722223426393388, 51.05181869560283)),
new MarkerFeature(createPoint(-2.2449710026111562, 53.47839876123808))
));
// Initialize popup styles
initPopupStyles();
// Add click handler for popup closer
popupCloser.addClickListener(e -> popup.setVisible(false));
}
private void initPopupStyles() {
// Styles are now defined in the CSS file
// We just need to make sure the popup is positioned correctly
popupCloser.setText("✖");
popupCloser.getStyle().set("background", "none");
popupCloser.getStyle().set("border", "none");
popupCloser.getStyle().set("cursor", "pointer");
popupCloser.getStyle().set("font-size", "16px");
popupCloser.getStyle().set("position", "absolute");
popupCloser.getStyle().set("top", "2px");
popupCloser.getStyle().set("right", "8px");
}
private void onVectorSourceClick(SourceFeatureClickNotifier.SourceFeatureClickEvent event) {
Point point = ((MarkerFeature) event.getFeature()).getPoint();
String pointText = point.toText();
// Get description for this point
String description = markerDescriptions.getOrDefault(pointText, "Location: " + pointText);
// Set popup content
popupContent.setText(description);
// We don't need to center the map, just show the popup
// Position the popup near the mouse cursor with a 30-pixel offset
int mouseX = event.getMouseEventDetails().getPageX();
int mouseY = event.getMouseEventDetails().getPageY();
// Use setTimeout to ensure the popup is rendered before calculating its height
UI.getCurrent().getPage().executeJs(
"const popup = document.querySelector('.ol-popup');" +
"if (popup) {" +
" popup.style.left = '" + (mouseX - 50) + "px';" +
" popup.style.top = '" + (mouseY - 10) + "px';" +
"popup.style.height = '50px';" + //todo bad solution, non-generic
" popup.style.transform = 'translate(0, -100%)';" +
"}"
);
// Show popup
popup.setVisible(true);
}
}
XML:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<view xmlns="http://jmix.io/schema/flowui/view" xmlns:maps="http://jmix.io/schema/maps/ui"
title="msg://com.company.jmixmapstest.view.mappoint/MapPointView.title">
<data>
<collection id="locationsDc" class="com.company.jmixmapstest.entity.MapPoint" fetchPlan="_base">
<loader id="mapsDl">
<query>
<![CDATA[select e from MapPoint e]]>
</query>
</loader>
</collection>
</data>
<facets>
<dataLoadCoordinator auto="true"/>
</facets>
<layout>
<div id="mapContainer" height="100%" width="100%">
<maps:geoMap id="map" height="100%" width="100%">
<maps:layers>
<maps:tile>
<maps:osmSource/>
</maps:tile>
<maps:vector id="markersLayer">
<maps:vectorSource id="markersSource"/>
</maps:vector>
<maps:vector id="dataVectorLayer">
<maps:dataVectorSource id="buildingSource" dataContainer="locationsDc" property="point"/>
</maps:vector>
<maps:vector id="vectorLayer">
<maps:vectorSource id="vectorSource"/>
</maps:vector>
</maps:layers>
<maps:mapView centerY="39.8" centerX="-98.6" zoom="4"/>
</maps:geoMap>
<div id="popup" visible="false" classNames="ol-popup">
<button id="popupCloser" classNames="ol-popup-closer"></button>
<div id="popupContent"></div>
</div>
</div>
</layout>
</view>
Styles(optional):
.ol-popup {
position: absolute;
background-color: white;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
padding: 15px;
border-radius: 10px;
border: 1px solid #cccccc;
bottom: 12px;
left: -50px;
min-width: 280px;
z-index: 1000;
height: auto;
min-height: fit-content;
max-width: 300px;
overflow-wrap: break-word;
}
.ol-popup:after, .ol-popup:before {
top: 100%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.ol-popup:after {
border-top-color: white;
border-width: 10px;
left: 48px;
margin-left: -10px;
}
.ol-popup:before {
border-top-color: #cccccc;
border-width: 11px;
left: 48px;
margin-left: -11px;
}
.ol-popup-closer {
text-decoration: none;
position: absolute;
top: 2px;
right: 8px;
}
.ol-popup-closer:after {
content: "✖";
}
DEMO:
jmix-maps-test.zip (257.3 KB)
Warn you that I did this solution as workaround and may contains overkill css(and other unnecessary staff like xml tags in screen) for popup and also, you can use not classic html tiptoes (like in open layer tutorial) but vaadin’s one.
Best regards,
Dmitry
Thank you @d.cherkasov
I will check, if I find a possibility with hover so there is no need of a click.
Best regards
Felix