Extending a custom component
In this tutorial we will see how we can customize an existing component. This tutorial is meant to be followed on a GeoGirafe instance installed by the create template.
Geogirafe comes with a lot of "core" components. One of them is the right click on the map that will open a menu with contextual information. By default, only coordinates are shown. In this tutorial we will add an extra information to it: the altitude above sea level based on a free web service.
The web service syntax is:
https://api.open-elevation.com/api/v1/lookup?locations=<LAT>,<LONG>
For instance:
https://api.open-elevation.com/api/v1/lookup?locations=46.99127,6.93749
You can find the final code of this tutorial here:
https://gitlab.com/geogirafe/gg-sample/-/tree/extend-existing-component
Prepare the code
- Make sure you have a
src/componentsfolder, if not create it. - Inside
src/componentsfolder create a new folder namedmy-context-menu. You could name it as you want. - Inside
src/components/my-context-menucreate acomponent.tsfile with this content:
import { MapDefaultContextMenuComponent } from "@geogirafe/lib-geoportal/components";
class MyContextMenuComponent extends MapDefaultContextMenuComponent {}
export default MyContextMenuComponent;
- Define the web component in
main.tswhen the app is ready:
import MyContextMenuComponent from './components/my-context-menu/component';
...
girafeApp.isReady().then(() => {
// Define custom components
customElements.define('my-first-component', MyFirstComponent);
customElements.define('my-extended-component', MyExtendedComponent);
customElements.define('my-context-menu', MyContextMenuComponent);
// Remove the splash-screen
splash.end();
});
Remember that a web component has to be named with a hyphen in it.
- Replace the existing
<girafe-default-context-menu>with yours inindex.html:
<girafe-app>
<header>
...
</header>
...
- <girafe-default-context-menu></girafe-default-context-menu>
+ <my-context-menu></my-context-menu>
If you run your app and the right click is working, you're now using your component even if you can't tell because we haven't add any customization yet.
- Create a
template.htmlinsrc/components/my-context-menudirectory:
<p>Hello World</p>
- Reference it in your component:
class MyContextMenuComponent extends MapDefaultContextMenuComponent {
templateUrl = './template.html'; // override the parent template
}
Now, when you right click you should see that GeoGirafe is using your component.
-
Let's copy the original template from the core code here: https://gitlab.com/geogirafe/gg-viewer/-/blob/main/src/components/context-menu/default-context-menu/template.html
-
Because we overrided the html template, create a new
style.cssfile insrc/components/my-context-menudirectory. Copy the content of those two CSS:
- https://gitlab.com/geogirafe/gg-viewer/-/blob/main/src/components/context-menu/default-context-menu/style.css
- https://gitlab.com/geogirafe/gg-viewer/-/blob/main/src/components/context-menu/mapcontextmenu.css
- Don't forget to reference it in the component:
class MyContextMenuComponent extends MapDefaultContextMenuComponent {
templateUrl = './template.html'; // overide the parent template
styleUrl = './style.css';
}
- Let's add a placeholder for our new height service, add a
<tr>at the end of the existing<table>:
...
<tr>
<td>Elevation</td>
<td id="contextmenu-elevation">0</td>
</tr>
</tbody>
</table>
...
- Create a new property in the component:
class MyContextMenuComponent extends MapDefaultContextMenuComponent {
templateUrl = './template.html'; // overide the parent template
styleUrl = './style.css';
height: number = -1000;
}
And reference it in the template:
...
<tr>
<td>Elevation</td>
<td id="contextmenu-elevation">${this.height}</td>
</tr>
</tbody>
</table>
...
- Now, let's add the logic in the component:
import { MapDefaultContextMenuComponent } from "@geogirafe/lib-geoportal/components";
import {toLonLat} from 'ol/proj';
class MyContextMenuComponent extends MapDefaultContextMenuComponent {
templateUrl = './template.html';
styleUrl = './style.css';
height: number = -1000;
async getRasterData(): Promise<void> {
const coords = toLonLat(this.mapContextMenuState.position);
const url = `https://api.open-elevation.com/api/v1/lookup?locations=${coords[1]},${coords[0]}`;
fetch(url).then(response => response.json()).then(data => {
this.height = data.results[0].elevation;
super.renderContent();
});
}
override showContextMenu(): void {
super.showContextMenu();
this.getRasterData();
}
}
This is not optimal at all, we're expecting the map to be in Web Mercator, i.e. 'EPSG:3857', we don't manage a possible error and we should show a spinner while we wait from the webservice. Such improvements are out of the scope of the present tutorial.
- That's it! When extending an existing component, it's important to understand the core plugin so you know what you'll extend and what you need to override.