I have a map in my angular app, generated through open layers library. I also have two layers, which show different data points. I can toggle them on and off depending on which ones i want to show in my html.
The map is showing perfectly and so are the data points for each layer. However, I am trying to add tooltips to my data points, so if they are hovered over with the mouse (while that particular layer is toggled on), a tooltip will appear showing the data point name.
Can anyone help me out with how i can add tooltips to this, because what i have added so far doesn’t seem to be working?
Here is my code so far for my component.ts file:
import { Component, OnInit } from "@angular/core";
import Map from "ol/Map";
import View from "ol/View";
import TileLayer from "ol/layer/Tile";
import VectorLayer from "ol/layer/Vector";
import OSM from "ol/source/OSM";
import { Feature } from "ol";
import { Point } from "ol/geom";
import { fromLonLat } from "ol/proj";
import VectorSource from "ol/source/Vector";
import { Style, Icon, Circle, Fill, Stroke } from "ol/style";
import Overlay from "ol/Overlay";
@Component({
selector: "map",
templateUrl: "./map.component.html",
styleUrls: ["./map.component.scss"],
})
export class MapComponent implements OnInit {
map: Map;
loading: any;
showLayer1: boolean = true;
showLayer2: boolean = true;
layer1: VectorLayer<VectorSource<Point>>;
layer2: VectorLayer<VectorSource<Point>>;
tooltipOverlay: Overlay;
constructor() {}
ngOnInit() {
this.loading = true;
setTimeout(() => {
// Create the map and add the OSM layer
this.map = new Map({
layers: [
new TileLayer({
source: new OSM(),
}),
],
target: "map",
});
const view = new View({
center: fromLonLat([-1.1432, 52.9548]), // Set the center coordinates
zoom: 7, // Adjust the zoom level as needed
});
this.map.setView(view);
// Create the tooltip overlay and add it to the map
this.tooltipOverlay = new Overlay({
element: document.getElementById("tooltip"),
autoPan: true,
});
this.map.addOverlay(this.tooltipOverlay);
// Create the vector source for layer 1
var layer1Source = new VectorSource<Point>({
features: [],
});
// Create the vector layer for layer 1 with the vector source
this.layer1 = new VectorLayer<VectorSource<Point>>({
source: layer1Source,
style: new Style({
image: new Icon({
src: "../../../assets/images/icons/ie.png",
imgSize: [24, 24],
crossOrigin: "anonymous",
}),
}),
});
// Create the vector source for layer 2
var layer2Source = new VectorSource<Point>({
features: [],
});
// Create the vector layer for layer 2 with the vector source
this.layer2 = new VectorLayer<VectorSource<Point>>({
source: layer2Source,
style: new Style({
image: new Circle({
radius: 8,
fill: new Fill({ color: "blue" }),
stroke: new Stroke({
color: "white",
width: 2,
}),
}),
}),
});
// Add the vector layers to the map initially
this.map.addLayer(this.layer1);
this.map.addLayer(this.layer2);
// Add markers for each school to layer 1
var shops1 = [
{
name: "shop1",
longitude: -3.892366,
latitude: 53.409634,
},
{
name: "shop2",
longitude: -0.147421,
latitude: 51.495373,
},
];
shops1.forEach((shop) => {
var marker = new Feature({
geometry: new Point(fromLonLat([shop.longitude, shop.latitude])),
name: shop.name,
});
layer1Source.addFeature(marker);
});
// Add markers for each shop to layer 2
var shops2 = [
{
name: "shop2",
longitude: -2.954443,
latitude: 53.402111,
},
{
name: "shop2",
longitude: -0.747971,
latitude: 51.314344,
},
// Add more shops for layer 2 as needed
];
shops2.forEach((shop) => {
var marker = new Feature({
geometry: new Point(fromLonLat([shop.longitude, shop.latitude])),
name: shop.name,
});
layer2Source.addFeature(marker);
});
this.loading = false;
}, 1000);
}
toggleLayer1() {
if (this.showLayer1) {
this.map.addLayer(this.layer1);
} else {
this.map.removeLayer(this.layer1);
}
}
toggleLayer2() {
if (this.showLayer2) {
this.map.addLayer(this.layer2);
} else {
this.map.removeLayer(this.layer2);
}
}
showTooltip(event) {
const feature = this.map.forEachFeatureAtPixel(
event.pixel,
(feature) => feature
);
if (feature) {
const geometry = feature.getGeometry();
if (geometry instanceof Point) {
const coordinates = geometry.getCoordinates();
this.tooltipOverlay.setPosition(coordinates);
const tooltipElement = this.tooltipOverlay.getElement();
tooltipElement.innerHTML = feature.get("name"); // Use any property of the feature to display in the tooltip
tooltipElement.style.display = "block";
}
} else {
this.hideTooltip();
}
}
hideTooltip() {
const tooltipElement = this.tooltipOverlay.getElement();
tooltipElement.style.display = "none";
}
}
Here is my html code:
<div class="app-content content">
<div class="content-wrapper">
<div class="row p-1 mt-5">
<div class="content-header"></div>
</div>
<div class="content-body" style="padding-top: 0px !important;">
<div class="row">
<div class="col">
<div>
<input
type="checkbox"
[(ngModel)]="showLayer1"
(change)="toggleLayer1()"
/>
Layer 1
</div>
</div>
<div class="col">
<div class="map-container">
<div id="map" class="map"></div>
<div id="tooltip" class="tooltip"></div>
</div>
</div>
<div class="col">
<div>
<input
type="checkbox"
[(ngModel)]="showLayer2"
(change)="toggleLayer2()"
/>
Layer 2
</div>
</div>
</div>
</div>
</div>
</div>
Here is my scss code:
.map-container {
width: 500px;
height: 500px;
}
.map {
width: 100%;
height: 100%;
}
.tooltip {
position: absolute;
display: none;
background-color: rgba(0, 0, 0, 0.8);
color: #fff;
padding: 5px;
font-size: 12px;
pointer-events: none;
z-index: 9999;
}