Add the iFrame app to host anything in the right bar - especially Custom Apps built with The Giraffe Javascript SDK 🧪
The Giraffe Javascript SDK allows developers to write custom web apps that extend the functionality of Giraffe. Apps can read and write data from the Giraffe map such as geometries, layers and UI state (eg a user’s current selection).
An app is rendered in an Iframe on the right of the screen. It can interact with other areas of Giraffe through the SDK functions.
Option 1
We have a repo with several examples. If you want to develop an app, this is the best place to start.
Option 2
If you’d prefer to start from scratch,
Install @gi-nx/iframe-sdk
(ie yarn add @gi-nx/iframe-sdk
) so that your SDK app can interact with Giraffe
import { giraffeState, rpc } from '@gi-nx/iframe-sdk';
If you use React hooks, install @gi-nx/iframe-sdk-react
. useGiraffeState
provides a convenient method to access the data from giraffeState
within React components.
Option 3
If you’d just like to play around, you can even dev in the browser using https://codesandbox.io/ .
Open https://codesandbox.io/p/sandbox/icy-https-xtmx83?file=%2Fsrc%2FApp.tsx%3A1%2C1
Open a project in Giraffe
Point Giraffe to the Codesandbox app url. The one that looks like *https://xtmx83-5173.csb.app/*
See step 3 below for where to enter the url into Giraffe
The App selector displays all of the apps you have available.
Search for Iframe by clicking the search icon
Navigate to ☰Main menu → Advanced → Json editor
Set the Iframe App Data to point to your SDK App’s URL
You can also add a URL for your app’s logo
The examples repo uses a lot (but not all) of the available functionality.
See the SDK type docs for more details on each function.
app to write - to be converted
import React, { useEffect, useRef, useState } from "react";
import mapboxgl from "mapbox-gl";
mapboxgl.accessToken = "YOUR_MAPBOX_ACCESS_TOKEN";
const MapController = () => {
const mapContainerRef = useRef(null);
const mapRef = useRef(null);
const [pitch, setPitch] = useState(0);
const [zoom, setZoom] = useState(10);
useEffect(() => {
if (mapContainerRef.current && !mapRef.current) {
mapRef.current = new mapboxgl.Map({
container: mapContainerRef.current,
style: "mapbox://styles/mapbox/streets-v11",
center: [0, 0],
zoom: zoom,
pitch: pitch,
});
}
}, []);
useEffect(() => {
if (mapRef.current) {
mapRef.current.setPitch(pitch);
mapRef.current.setZoom(zoom);
}
}, [pitch, zoom]);
return (
<div className="flex flex-col items-center p-4">
<div ref={mapContainerRef} className="w-full h-[500px] rounded-lg shadow-md" />
<div className="mt-4 w-full max-w-md">
<label className="block">Pitch: {pitch}°</label>
<input
type="range"
min="0"
max="60"
value={pitch}
onChange={(e) => setPitch(Number(e.target.value))}
className="w-full"
/>
<label className="block mt-2">Zoom: {zoom}</label>
<input
type="range"
min="1"
max="20"
value={zoom}
onChange={(e) => setZoom(Number(e.target.value))}
className="w-full"
/>
</div>
</div>
);
};
export default MapController;