mirror of
https://github.com/noodlapp/noodl-docs.git
synced 2026-01-11 14:52:54 +01:00
Initial commit
Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com> Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com> Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com> Co-Authored-By: Michael Cartner <32543275+michaelcartner@users.noreply.github.com>
This commit is contained in:
109
library/modules/mapbox/guides/3d-model.md
Normal file
109
library/modules/mapbox/guides/3d-model.md
Normal file
@@ -0,0 +1,109 @@
|
||||
https://docs.mapbox.com/mapbox-gl-js/example/add-3d-model/
|
||||
|
||||
```js
|
||||
const map = Inputs.map;
|
||||
|
||||
// parameters to ensure the model is georeferenced correctly on the map
|
||||
const modelOrigin = [148.9819, -35.39847];
|
||||
const modelAltitude = 0;
|
||||
const modelRotate = [Math.PI / 2, 0, 0];
|
||||
|
||||
const modelAsMercatorCoordinate = mapboxgl.MercatorCoordinate.fromLngLat(
|
||||
modelOrigin,
|
||||
modelAltitude
|
||||
);
|
||||
|
||||
// transformation parameters to position, rotate and scale the 3D model onto the map
|
||||
const modelTransform = {
|
||||
translateX: modelAsMercatorCoordinate.x,
|
||||
translateY: modelAsMercatorCoordinate.y,
|
||||
translateZ: modelAsMercatorCoordinate.z,
|
||||
rotateX: modelRotate[0],
|
||||
rotateY: modelRotate[1],
|
||||
rotateZ: modelRotate[2],
|
||||
/* Since the 3D model is in real world meters, a scale transform needs to be
|
||||
* applied since the CustomLayerInterface expects units in MercatorCoordinates.
|
||||
*/
|
||||
scale: modelAsMercatorCoordinate.meterInMercatorCoordinateUnits()
|
||||
};
|
||||
|
||||
const THREE = window.THREE;
|
||||
|
||||
// configuration of the custom layer for a 3D model per the CustomLayerInterface
|
||||
const customLayer = {
|
||||
id: '3d-model',
|
||||
type: 'custom',
|
||||
renderingMode: '3d',
|
||||
onAdd: function (map, gl) {
|
||||
this.camera = new THREE.Camera();
|
||||
this.scene = new THREE.Scene();
|
||||
|
||||
// create two three.js lights to illuminate the model
|
||||
const directionalLight = new THREE.DirectionalLight(0xffffff);
|
||||
directionalLight.position.set(0, -70, 100).normalize();
|
||||
this.scene.add(directionalLight);
|
||||
|
||||
const directionalLight2 = new THREE.DirectionalLight(0xffffff);
|
||||
directionalLight2.position.set(0, 70, 100).normalize();
|
||||
this.scene.add(directionalLight2);
|
||||
|
||||
// use the three.js GLTF loader to add the 3D model to the three.js scene
|
||||
const loader = new THREE.GLTFLoader();
|
||||
loader.load(
|
||||
'https://docs.mapbox.com/mapbox-gl-js/assets/34M_17/34M_17.gltf',
|
||||
(gltf) => {
|
||||
this.scene.add(gltf.scene);
|
||||
}
|
||||
);
|
||||
this.map = map;
|
||||
|
||||
// use the Mapbox GL JS map canvas for three.js
|
||||
this.renderer = new THREE.WebGLRenderer({
|
||||
canvas: map.getCanvas(),
|
||||
context: gl,
|
||||
antialias: true
|
||||
});
|
||||
|
||||
this.renderer.autoClear = false;
|
||||
},
|
||||
render: function (gl, matrix) {
|
||||
const rotationX = new THREE.Matrix4().makeRotationAxis(
|
||||
new THREE.Vector3(1, 0, 0),
|
||||
modelTransform.rotateX
|
||||
);
|
||||
const rotationY = new THREE.Matrix4().makeRotationAxis(
|
||||
new THREE.Vector3(0, 1, 0),
|
||||
modelTransform.rotateY
|
||||
);
|
||||
const rotationZ = new THREE.Matrix4().makeRotationAxis(
|
||||
new THREE.Vector3(0, 0, 1),
|
||||
modelTransform.rotateZ
|
||||
);
|
||||
|
||||
const m = new THREE.Matrix4().fromArray(matrix);
|
||||
const l = new THREE.Matrix4()
|
||||
.makeTranslation(
|
||||
modelTransform.translateX,
|
||||
modelTransform.translateY,
|
||||
modelTransform.translateZ
|
||||
)
|
||||
.scale(
|
||||
new THREE.Vector3(
|
||||
modelTransform.scale,
|
||||
-modelTransform.scale,
|
||||
modelTransform.scale
|
||||
)
|
||||
)
|
||||
.multiply(rotationX)
|
||||
.multiply(rotationY)
|
||||
.multiply(rotationZ);
|
||||
|
||||
this.camera.projectionMatrix = m.multiply(l);
|
||||
this.renderer.resetState();
|
||||
this.renderer.render(this.scene, this.camera);
|
||||
this.map.triggerRepaint();
|
||||
}
|
||||
};
|
||||
|
||||
map.addLayer(customLayer, 'waterway-label');
|
||||
```
|
||||
21
library/modules/mapbox/guides/camera.md
Normal file
21
library/modules/mapbox/guides/camera.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Camera
|
||||
|
||||
## Fly to location
|
||||
|
||||
```js
|
||||
const mapboxObject = Inputs.MapboxObject;
|
||||
if (!mapboxObject) return;
|
||||
|
||||
// Mapbox example
|
||||
// https://docs.mapbox.com/mapbox-gl-js/example/flyto/
|
||||
|
||||
// flyTo doc:
|
||||
// https://docs.mapbox.com/mapbox-gl-js/api/map/#map#flyto
|
||||
mapboxObject.flyTo({
|
||||
center: [(Math.random() - 0.5) * 360, (Math.random() - 0.5) * 100],
|
||||
zoom: 10,
|
||||
// this animation is considered essential
|
||||
// with respect to prefers-reduced-motion
|
||||
essential: true,
|
||||
});
|
||||
```
|
||||
253
library/modules/mapbox/guides/directions-api/README.md
Normal file
253
library/modules/mapbox/guides/directions-api/README.md
Normal file
@@ -0,0 +1,253 @@
|
||||
---
|
||||
title: Directions API with the Mapbox Module
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Directions API with the Mapbox Module
|
||||
|
||||
Here are some code heavy example of how to use the Directions API in Noodl.
|
||||
The code in this example is using [Getting started with the Mapbox Directions API
|
||||
](https://docs.mapbox.com/help/tutorials/getting-started-directions-api/) guide.
|
||||
|
||||
## Listen to on click events on Mapbox
|
||||
|
||||
Script node:
|
||||
|
||||
```js
|
||||
Script.Outputs = {
|
||||
["Mapbox Object"]: "*",
|
||||
["Clicked"]: "signal",
|
||||
["Clicked Longitude"]: "number",
|
||||
["Clicked Latitute"]: "number"
|
||||
};
|
||||
|
||||
Script.Signals["Mount Click Event"] = function () {
|
||||
// Listen to the Mapbox on click event
|
||||
// NOTE: This might cause some memory leaks,
|
||||
// Not sure how Mapbox is handling it.
|
||||
Script.Inputs["Mapbox Object"].on("click", (event) => {
|
||||
// Get the coordinates that the user pressed on
|
||||
const coords = Object.keys(event.lngLat).map((key) => event.lngLat[key]);
|
||||
|
||||
// Set the Noodl outputs
|
||||
Script.Outputs["Clicked Longitude"] = coords[0];
|
||||
Script.Outputs["Clicked Latitute"] = coords[1];
|
||||
|
||||
// Send the click signal
|
||||
Script.Outputs["Clicked"]();
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
## Create a route path on Mapbox
|
||||
|
||||
Script node:
|
||||
|
||||
```js
|
||||
// This function makes a Mapbox Directions API request
|
||||
async function getRoute(map, start, end) {
|
||||
const accessToken = Noodl.getProjectSettings().mapboxAccessToken;
|
||||
|
||||
// make a directions request using cycling profile
|
||||
// an arbitrary start will always be the same
|
||||
// only the end or destination will change
|
||||
const query = await fetch(
|
||||
`https://api.mapbox.com/directions/v5/mapbox/cycling/${start[0]},${start[1]};${end[0]},${end[1]}?steps=true&geometries=geojson&access_token=${accessToken}`,
|
||||
{ method: "GET" }
|
||||
);
|
||||
const json = await query.json();
|
||||
const data = json.routes[0];
|
||||
const route = data.geometry.coordinates;
|
||||
const geojson = {
|
||||
type: "Feature",
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: "LineString",
|
||||
coordinates: route,
|
||||
},
|
||||
};
|
||||
// if the route already exists on the map, we'll reset it using setData
|
||||
if (map.getSource("route")) {
|
||||
map.getSource("route").setData(geojson);
|
||||
}
|
||||
// otherwise, we'll make a new request
|
||||
else {
|
||||
map.addLayer({
|
||||
id: "route",
|
||||
type: "line",
|
||||
source: {
|
||||
type: "geojson",
|
||||
data: geojson,
|
||||
},
|
||||
layout: {
|
||||
"line-join": "round",
|
||||
"line-cap": "round",
|
||||
},
|
||||
paint: {
|
||||
"line-color": "#3887be",
|
||||
"line-width": 5,
|
||||
"line-opacity": 0.75,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
//
|
||||
// Start of Noodl Script
|
||||
//
|
||||
|
||||
Script.Inputs = {
|
||||
map: {
|
||||
displayName: "Mapbox Object",
|
||||
type: "*",
|
||||
},
|
||||
|
||||
startLongitude: {
|
||||
displayName: "Start Longitude",
|
||||
type: "number",
|
||||
group: "Coordinates",
|
||||
default: 0,
|
||||
},
|
||||
startLatitute: {
|
||||
displayName: "Start Latitude",
|
||||
type: "number",
|
||||
group: "Coordinates",
|
||||
default: 0,
|
||||
},
|
||||
|
||||
endLongitude: {
|
||||
displayName: "End Longitude",
|
||||
type: "number",
|
||||
group: "Coordinates",
|
||||
default: 0,
|
||||
},
|
||||
endLatitute: {
|
||||
displayName: "End Latitude",
|
||||
type: "number",
|
||||
group: "Coordinates",
|
||||
default: 0,
|
||||
},
|
||||
|
||||
// You can read more about Routing profiles here:
|
||||
// https://docs.mapbox.com/api/navigation/directions/#routing-profiles
|
||||
routingProfile: {
|
||||
displayName: "Routing Profile",
|
||||
type: {
|
||||
name: "enum",
|
||||
enums: [
|
||||
{
|
||||
label: "Driving Traffic",
|
||||
value: "mapbox/driving-traffic",
|
||||
},
|
||||
{
|
||||
label: "Driving",
|
||||
value: "mapbox/driving",
|
||||
},
|
||||
{
|
||||
label: "Walking",
|
||||
value: "mapbox/walking",
|
||||
},
|
||||
{
|
||||
label: "Cycling",
|
||||
value: "mapbox/cycling",
|
||||
},
|
||||
],
|
||||
},
|
||||
default: "mapbox/cycling",
|
||||
},
|
||||
};
|
||||
|
||||
Script.Outputs = {
|
||||
Steps: "array",
|
||||
Duration: "number",
|
||||
};
|
||||
|
||||
Script.Signals.CreateRoute = function () {
|
||||
const map = Script.Inputs.Map;
|
||||
const startCoords = [
|
||||
Script.Inputs.startLongitude,
|
||||
Script.Inputs.startLatitute,
|
||||
];
|
||||
const endCoords = [Script.Inputs.endLongitude, Script.Inputs.endLatitute];
|
||||
|
||||
// Add starting point to the map
|
||||
map.addLayer({
|
||||
id: "point",
|
||||
type: "circle",
|
||||
source: {
|
||||
type: "geojson",
|
||||
data: {
|
||||
type: "FeatureCollection",
|
||||
features: [
|
||||
{
|
||||
type: "Feature",
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: "Point",
|
||||
coordinates: startCoords,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
paint: {
|
||||
"circle-radius": 10,
|
||||
"circle-color": "#3887be",
|
||||
},
|
||||
});
|
||||
|
||||
const endPoint = {
|
||||
type: "FeatureCollection",
|
||||
features: [
|
||||
{
|
||||
type: "Feature",
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: "Point",
|
||||
coordinates: endCoords,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
if (map.getLayer("end")) {
|
||||
map.getSource("end").setData(endPoint);
|
||||
} else {
|
||||
map.addLayer({
|
||||
id: "end",
|
||||
type: "circle",
|
||||
source: {
|
||||
type: "geojson",
|
||||
data: {
|
||||
type: "FeatureCollection",
|
||||
features: [
|
||||
{
|
||||
type: "Feature",
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: "Point",
|
||||
coordinates: endCoords,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
paint: {
|
||||
"circle-radius": 10,
|
||||
"circle-color": "#f30",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// make an directions request that
|
||||
getRoute(map, startCoords, endCoords).then((data) => {
|
||||
// Extract the steps / instructions
|
||||
const steps = data.legs[0].steps;
|
||||
Script.Outputs.Steps = steps;
|
||||
|
||||
Script.Outputs.Duration = Math.floor(data.duration / 60);
|
||||
});
|
||||
};
|
||||
```
|
||||
131
library/modules/mapbox/guides/directions.md
Normal file
131
library/modules/mapbox/guides/directions.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# Directions
|
||||
|
||||
|
||||
|
||||
## Create a request to Directions API
|
||||
|
||||
TODO: Add more info about "overview" (full, simplified, or false)
|
||||
|
||||
```js
|
||||
// Get the Mapbox access token from Noodl project settings
|
||||
const access_token = Noodl.getProjectSettings().mapboxAccessToken;
|
||||
|
||||
// For using the API to handle min/max road width, we have to use the "driving" profile.
|
||||
// https://docs.mapbox.com/api/navigation/directions#optional-parameters-for-the-mapboxdriving-profile
|
||||
const routingProfile = "driving";
|
||||
|
||||
// Encode the coordinates to be URL-safe
|
||||
const coordinates = encodeURIComponent([fromCoordinate, toCoordinate].join(";"));
|
||||
|
||||
// Define query parameters for the API request
|
||||
//
|
||||
// Playground by Mapbox to test out all the features:
|
||||
// https://docs.mapbox.com/playground/directions/
|
||||
const queryParams = {
|
||||
access_token, // Provide the access token
|
||||
alternatives: true,
|
||||
continue_straight: true,
|
||||
geometries: "geojson",
|
||||
language: "en",
|
||||
overview: "simplified",
|
||||
steps: true,
|
||||
// The max vehicle height, in meters. If this parameter is provided, the
|
||||
// Directions API will compute a route that includes only roads with a height
|
||||
// limit greater than or equal to the max vehicle height. max_height must be
|
||||
// between 0 and 10 meters. The default value is 1.6 meters. Coverage for road
|
||||
// height restriction may vary by region.
|
||||
max_height,
|
||||
// The max vehicle width, in meters. If this parameter is provided, the
|
||||
// Directions API will compute a route that includes only roads with a width
|
||||
// limit greater than or equal to the max vehicle width. max_width must be
|
||||
// between 0 and 10 meters. The default value is 1.9 meters. Coverage for road
|
||||
// width restriction may vary by region.
|
||||
max_width,
|
||||
};
|
||||
|
||||
// Construct the query string from the query parameters
|
||||
const query = Object.keys(queryParams)
|
||||
.filter((key) => !!queryParams[key]) // Filter out empty values
|
||||
.map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(queryParams[key])}`)
|
||||
.join('&');
|
||||
|
||||
// Set the endpoint URL for the Mapbox directions API
|
||||
const ENDPOINT = 'https://api.mapbox.com/directions/v5/mapbox';
|
||||
|
||||
// Make the API request and get the response as JSON
|
||||
const response = await fetch(`${ENDPOINT}/${routingProfile}/${coordinates}?${query}`);
|
||||
const json = await response.json();
|
||||
|
||||
if (json.code === "Ok") {
|
||||
Outputs.Routes = jsonroutes;
|
||||
Outputs.Success();
|
||||
} else {
|
||||
Outputs.Failure();
|
||||
}
|
||||
```
|
||||
|
||||
Draw the route:
|
||||
```js
|
||||
Script.Inputs = {
|
||||
MapboxObject: "object",
|
||||
Routes: "array"
|
||||
};
|
||||
|
||||
Script.Outputs = {
|
||||
Done: "signal",
|
||||
};
|
||||
|
||||
|
||||
Script.Signals = {
|
||||
Update() {
|
||||
const map = Script.Inputs.MapboxObject;
|
||||
|
||||
const route = Script.Inputs.Routes[0];
|
||||
|
||||
function createOrUpdateSource(id, newSource) {
|
||||
const source = map.getSource(id);
|
||||
if (source) {
|
||||
source.setData(newSource.data);
|
||||
} else {
|
||||
map.addSource(id, newSource);
|
||||
}
|
||||
}
|
||||
|
||||
function createOrUpdateLayer(newLayer) {
|
||||
const layer = map.getLayer(newLayer.id);
|
||||
if (layer) {
|
||||
if (newLayer.paint) {
|
||||
Object.keys(newLayer.paint).forEach((key) => {
|
||||
layer.setPaintProperty(key, newLayer.paint[key]);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
map.addLayer(newLayer);
|
||||
}
|
||||
}
|
||||
|
||||
createOrUpdateSource('route', {
|
||||
'type': 'geojson',
|
||||
'data': {
|
||||
'type': 'Feature',
|
||||
'properties': {},
|
||||
'geometry': route.geometry,
|
||||
}
|
||||
});
|
||||
|
||||
createOrUpdateLayer({
|
||||
'id': 'route',
|
||||
'type': 'line',
|
||||
'source': 'route',
|
||||
'layout': {
|
||||
'line-join': 'round',
|
||||
'line-cap': 'round'
|
||||
},
|
||||
'paint': {
|
||||
'line-color': '#888',
|
||||
'line-width': 8
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
```
|
||||
111
library/modules/mapbox/guides/geocoder.md
Normal file
111
library/modules/mapbox/guides/geocoder.md
Normal file
@@ -0,0 +1,111 @@
|
||||
---
|
||||
title: Geocoder
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Geocoder
|
||||
|
||||
Mapbox Geocoder API is a geocoding service that allows developers to convert human-readable addresses into geographic coordinates (latitude and longitude) and vice versa. It is a RESTful API that provides geocoding and reverse geocoding services for worldwide locations. The API uses machine learning and other advanced algorithms to provide accurate and relevant results for address searches. Mapbox Geocoder API can be used in a variety of applications, such as location-based services, logistics and delivery management, real estate, and more. It also offers various features such as autocomplete suggestions, batch geocoding, and custom matching parameters, making it a powerful tool for developers to build location-based applications.
|
||||
|
||||
## Create a request to Geocoder API
|
||||
|
||||
```js
|
||||
// Define the expected inputs for the script
|
||||
Script.Inputs = {
|
||||
Query: "string",
|
||||
};
|
||||
|
||||
// Define the expected outputs for the script
|
||||
Script.Outputs = {
|
||||
Items: "array",
|
||||
Searched: "signal",
|
||||
};
|
||||
|
||||
// Set the endpoint URL for the Mapbox geocoding API
|
||||
const ENDPOINT = "https://api.mapbox.com/geocoding/v5/mapbox.places";
|
||||
|
||||
// Define an asynchronous function to make the API request
|
||||
async function makeRequest() {
|
||||
// Get the Mapbox access token from Noodl project settings
|
||||
const access_token = Noodl.getProjectSettings().mapboxAccessToken;
|
||||
|
||||
// Encode the search query to be URL-safe
|
||||
const search_text = encodeURIComponent(Script.Inputs.Query);
|
||||
|
||||
// Define query parameters for the API request
|
||||
//
|
||||
// Playground by Mapbox to test out all the features:
|
||||
// https://docs.mapbox.com/playground/geocoding
|
||||
//
|
||||
// Here is a list of all the different possible types:
|
||||
// - address
|
||||
// - country
|
||||
// - region
|
||||
// - postcode
|
||||
// - district
|
||||
// - place
|
||||
// - neighborhood
|
||||
// - locality
|
||||
// - poi
|
||||
const queryParams = {
|
||||
access_token, // Provide the access token
|
||||
proximity: "ip", // Bias results towards user's location
|
||||
limit: 5, // Maximum number of results to return
|
||||
types: ["address"].join(","), // Filter results to include only addresses
|
||||
fuzzyMatch: true, // Enable approximate matching
|
||||
};
|
||||
|
||||
// Construct the query string from the query parameters
|
||||
const query = Object.keys(queryParams)
|
||||
.filter((key) => !!queryParams[key]) // Filter out empty values
|
||||
.map(
|
||||
(key) =>
|
||||
`${encodeURIComponent(key)}=${encodeURIComponent(queryParams[key])}`
|
||||
)
|
||||
.join("&");
|
||||
|
||||
// Make the API request and get the response as JSON
|
||||
const response = await fetch(`${ENDPOINT}/${search_text}.json?${query}`);
|
||||
const json = await response.json();
|
||||
|
||||
// Map the API response to an array of search results
|
||||
const items = json.features.map((x) =>
|
||||
Noodl.Object.create({
|
||||
text: x.text,
|
||||
place_name: x.place_name,
|
||||
// Convert the array of [latitude, longitude] to a Geopoint
|
||||
center: { latitude: x.center[0], longitude: x.center[1] },
|
||||
})
|
||||
);
|
||||
|
||||
Script.Outputs.Items = items;
|
||||
Script.Outputs.Searched();
|
||||
}
|
||||
|
||||
Script.Signals = {
|
||||
Search() {
|
||||
makeRequest();
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Improve the search result
|
||||
|
||||
While comparing the built in Geocoder in Mapbox and using this Script.
|
||||
There are a few differences and the result from the Mapbox Geocoder is getting better result.
|
||||
|
||||
The reason why the results are better is that the parameters are a little different, but in the end they are using the same API endpoints.
|
||||
|
||||
To make the parameters match, we can make a few changes in this code:
|
||||
|
||||
```js
|
||||
const queryParams = {
|
||||
access_token, // Provide the access token
|
||||
proximity: [Script.Inputs.lng, Script.Inputs.lat].join(','), // Bias results towards user's location
|
||||
limit: 5, // Maximum number of results to return
|
||||
language: 'en-GB'
|
||||
};
|
||||
```
|
||||
|
||||
The main change here is the `proximity` that we changed to a Geopoint instead of `ip`.
|
||||
This requires 2 new inputs to the Script node, `lng` and `lat`, connected from the Mapbox node center lng and lat position.
|
||||
111
library/modules/mapbox/guides/interacting/README.md
Normal file
111
library/modules/mapbox/guides/interacting/README.md
Normal file
@@ -0,0 +1,111 @@
|
||||
---
|
||||
title: Interacting with the Mapbox Module
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Interacting with the Mapbox Module
|
||||
|
||||
## What you will learn in this guide
|
||||
|
||||
This guide will teach you how to implement basic interactions with your Mapbox map using the Mapbox Module.
|
||||
|
||||
## Overview
|
||||
|
||||
If you haven't setup Mapbox, it is recommended to read [setting up Mapbox guide](/library/modules/mapbox/guides/setting-up) before continuing this guide.
|
||||
|
||||
We will go though the following steps:
|
||||
|
||||
- Getting the latitude and longitude of the position a user clicked on the map.
|
||||
- Detecting when a user moves the map.
|
||||
|
||||
## Getting the position that the user clicked
|
||||
|
||||
If we start out with the same super simple app as in the previous guide ([Setting up](/library/modules/mapbox/guides/setting-up) guide) we can start adding some interactions to it.
|
||||
|
||||
<div className="ndl-image-with-background l">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
Let's first remove the "Hello World"-text. Instead we replace it with a panel. We will build it using a [Group](/nodes/basic-elements/group) node. So add a **Group** node at the bottom of the node hierarchy. Name it "Popup Panel" for readability.
|
||||
|
||||
<div className="ndl-image-with-background">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
We want it to float on top of the Mapbox Map so change it's **Position** to **Absolute**. Center it and dock it to the bottom using the **Layout** controls. Set a size of 300 pixels wide and 100 pixels high for now. Give it a bottom margin of 20 pixels to give it some space.
|
||||
|
||||
<div className="ndl-image-with-background s">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
Also make it white, with rounded corners of 10 pixels and a 2 pixel outline of a dark grey color. Also tick `Shadow Enabled` to make it a little nicer visually.
|
||||
|
||||
<div className="ndl-image-with-background s">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
Now you should have a panel floating on top of the map.
|
||||
|
||||
<div className="ndl-image-with-background l">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
We want to print out the geographical location in the panel, i.e. the latitude and longitude of the position the user clicks.
|
||||
|
||||
Add two text nodes in the panel. Adjust the padding (horizontally and vertically) of the "Popup Panel" to 10 pixels to give the text some space.
|
||||
|
||||
<div className="ndl-image-with-background l">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
Then connect the two outputs `Longitude` and `Latitude` to the respective text.
|
||||
|
||||
_Make sure it's the one under "Mapped Clicked" Section_ since there are two other similarly named outputs that holds the current panning position of the map.
|
||||
|
||||
<div className="ndl-image-with-background l">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
Now try clicking around in the map. You should see the two texts updating whenever you click.
|
||||
|
||||
<div className="ndl-image-with-background l">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
## Tracking Map Movement
|
||||
|
||||
Now let's add some behavior to the panel. We want it to appear from the bottom when the user clicks on the map. Then, when the user starts panning or zooming in the map. To do this we are going to use the `Click` and `Map Moved` output signals.
|
||||
|
||||
First add a [States](/nodes/utilities/logic/states) node that will hold the current state of the panel. Add the states "Off Screen" and "On Screen". Create a value to control in the state, lets call it "Y Position". This is the value that will control the Y position of the panel. It will be 120 when the panel is "Off Screen" (i.e. it will be below the screen). Then it will be 0 when the panel is "On Screen", i.e. it will be back at the bottom of the screen.
|
||||
|
||||
<div className="ndl-image-with-background">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
Finally hook up the outputs `Click` and `Map Moved` signal to change the state between "On Screen" and "Off Screen". Feed back the output "Y Position" to the **Pos Y** of the panel.
|
||||
|
||||
<div className="ndl-image-with-background l">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
Now you should be able to move around and click on the map, showing and hiding the panel printing the longitude and latitude.
|
||||
49
library/modules/mapbox/guides/polygon.md
Normal file
49
library/modules/mapbox/guides/polygon.md
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
WIP, would be nice to work with the nodes.
|
||||
|
||||
```js
|
||||
const mapbox = Inputs.MapboxObject;
|
||||
const draw = new MapboxDraw({
|
||||
displayControlsDefault: false,
|
||||
// Select which mapbox-gl-draw control buttons to add to the map.
|
||||
controls: {
|
||||
polygon: true,
|
||||
trash: true
|
||||
},
|
||||
// Set mapbox-gl-draw to draw by default.
|
||||
// The user does not have to click the polygon control button first.
|
||||
defaultMode: 'draw_polygon'
|
||||
});
|
||||
mapbox.addControl(draw);
|
||||
|
||||
|
||||
function updateArea(e) {
|
||||
const geometry = e.features[0].geometry;
|
||||
Outputs.Geometry = JSON.parse(JSON.stringify(geometry));
|
||||
Outputs.Coordinates = geometry.coordinates;
|
||||
|
||||
// const data = draw.getAll();
|
||||
// const answer = document.getElementById('calculated-area') = Outputs.calculatedarea;
|
||||
// if (data.features.length > 0) {
|
||||
// const area = turf.area(data);
|
||||
// // Restrict the area to 2 decimal points.
|
||||
// const rounded_area = Math.round(area * 100) / 100;
|
||||
// answer.innerHTML = `<p><strong>${rounded_area}</strong></p><p>square meters</p>`;
|
||||
// } else {
|
||||
// answer.innerHTML = '';
|
||||
// if (e.type !== 'draw.delete')
|
||||
// alert('Click the map to draw a polygon.');
|
||||
// }
|
||||
}
|
||||
|
||||
mapbox.on('draw.create', updateArea);
|
||||
mapbox.on('draw.delete', updateArea);
|
||||
mapbox.on('draw.update', updateArea);
|
||||
|
||||
// Add keydown event listener to the mapbox container
|
||||
mapbox.getCanvas().addEventListener('keydown', (event) => {
|
||||
if (event.keyCode === 13 || event.keyCode === 3) { // 13 is the keycode for the Enter key
|
||||
draw.changeMode('simple_select');
|
||||
}
|
||||
});
|
||||
```
|
||||
45
library/modules/mapbox/guides/screen-coordinates/README.md
Normal file
45
library/modules/mapbox/guides/screen-coordinates/README.md
Normal file
@@ -0,0 +1,45 @@
|
||||
---
|
||||
title: Getting Screen Coordinates of Markers
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Getting Screen Coordinates of Markers
|
||||
|
||||
:::caution
|
||||
|
||||
With the new Mapbox module you only need to place your nodes as children to the Mapbox Marker, and they will be visible instead.
|
||||
|
||||
:::
|
||||
|
||||
This snippet is useful if you want to position something, for example a Noodl Component, on top of a Marker on the Mapbox Map.
|
||||
|
||||
<div className="ndl-image-with-background l">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
## How it works
|
||||
|
||||
Create a [Function](/nodes/javascript/function) node and paste in the code below
|
||||
|
||||
```javascript
|
||||
const markers = document.querySelectorAll(".mapboxgl-marker");
|
||||
|
||||
if (!markers) return;
|
||||
|
||||
for (let i = 0; i < markers.length; i++) {
|
||||
let m = markers[i];
|
||||
let markerId = m.getAttribute("data-ndl-marker-id");
|
||||
let rect = m.getBoundingClientRect();
|
||||
|
||||
Noodl.Object.get(markerId).setAll({
|
||||
posX: rect.left,
|
||||
posY: rect.top,
|
||||
});
|
||||
}
|
||||
|
||||
Outputs.done();
|
||||
```
|
||||
|
||||
When calling **Run** on the **Function** node the screen coordinates will be written to the Marker array, in the two properties `posX` and `posY`. After the operation is finished the **Done** output signal will be triggered.
|
||||
58
library/modules/mapbox/guides/screenshot.md
Normal file
58
library/modules/mapbox/guides/screenshot.md
Normal file
@@ -0,0 +1,58 @@
|
||||
---
|
||||
title: Take a screenshot
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Take a screenshot
|
||||
|
||||
Taking a screenshot of the map can be useful in many different scenarios,
|
||||
for example saving navigation, directions, planning, record-keeping, and research purposes.
|
||||
It can help visualize routes, distances, specific locations, and patterns in data.
|
||||
|
||||
:::info
|
||||
|
||||
This will not include Markers, to include Markers we have to take the screenshot in a different way.
|
||||
|
||||
:::
|
||||
|
||||
## Results
|
||||
|
||||
When taking the screenshot we will get an image the same size as the Mapbox element.
|
||||
|
||||
The output will be an image blob which can be passed into an Image node, upload as a file, or saved in the database.
|
||||
|
||||
Example of the screenshot/image data format:
|
||||
```
|
||||
data:image/png;base64,iVBORw0KGgoA...
|
||||
```
|
||||
|
||||
This is what the image looks like:
|
||||
|
||||
<div className="ndl-image-with-background">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
## Steps
|
||||
|
||||
1. Create a Function node, with this code:
|
||||
```js
|
||||
const mapboxObject = Inputs.MapboxObject;
|
||||
if (!mapboxObject) return;
|
||||
|
||||
Outputs.ImageDataUrl = mapboxObject.getCanvas().toDataURL();
|
||||
```
|
||||
|
||||
2. Connect the Mapbox Output, `Mapbox Object` to the Function node.
|
||||
|
||||
3. Connect the `ImageDataUrl` output on the Function node to either an image or where you want to save it.
|
||||
This image can be saved in the database too, but keep in mind that it is not recommended to save a lot of data in a column.
|
||||
|
||||
Here is an example of how it might look in the end:
|
||||
|
||||
<div className="ndl-image-with-background">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
66
library/modules/mapbox/guides/setting-up/README.md
Normal file
66
library/modules/mapbox/guides/setting-up/README.md
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
title: Setting up the Mapbox Module
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Setting up the Mapbox Module
|
||||
|
||||
## What you will learn in this guide
|
||||
|
||||
This guide will show you how to include the Mapbox module in a project and set up an Mapbox API key to use for your application.
|
||||
|
||||
## Overview
|
||||
|
||||
We will go though the following steps:
|
||||
|
||||
- Install the Mapbox Module in a Noodl Project.
|
||||
- Create an Access Token on the Mapbox account
|
||||
- Create a minimal Mapbox App in Noodl
|
||||
|
||||
## Install the Mapbox Module
|
||||
|
||||
When in the project, open the "Module" tab in the Node Picker. Find the "Mapbox" module and click "Install".
|
||||
|
||||
<div className="ndl-image-with-background s">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
After the module is imported, you should now be able to find the [Mapbox Map](library/modules/mapbox/nodes/v2/mapbox-map) node in the node picker. Right click in the node editor area to bring up the node picker. Look under "External libraries" to find the **Mapbox Map** node.
|
||||
|
||||
<div className="ndl-image-with-background s">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
Add the node. Then put it as a child to your main App group. As you will see, you will immedieatly get a warning: _"No access token. Please specify one in the Project Settings and reload"_.
|
||||
|
||||
<div className="ndl-image-with-background">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
So to use the Mapbox Module you need an access token from Mapbox. You can read more about Access tokens [here](https://docs.mapbox.com/help/getting-started/access-tokens/) and also follow instructions on how to create one. Among other things you will have to set up an account on Mapbox unless you already have one.
|
||||
|
||||
## Entering the Mapbox Access Token
|
||||
|
||||
Once you got the token (which will look like a long password) you open up the "Project Settings" panel by clicking the cogwheel in the main panel to the left. Copy/Paste the token into the field called "Mapbox Access Token"
|
||||
|
||||
<div className="ndl-image-with-background">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
Once you've added in the token, reload the viewer, and you should now have a Mapbox map showing in your App, something like below.
|
||||
|
||||
<div className="ndl-image-with-background">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
You can play a little with the map. Pan and zoom.
|
||||
134
library/modules/mapbox/guides/styles.md
Normal file
134
library/modules/mapbox/guides/styles.md
Normal file
@@ -0,0 +1,134 @@
|
||||
---
|
||||
title: Mapbox Styles
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Mapbox Styles
|
||||
|
||||
Mapbox styles are a collection of rules that define how a map is displayed. They include information about the map's layout, colors, labels, and symbols. Mapbox styles are used to create maps that are visually appealing and easy to read.
|
||||
|
||||
They can be customized to meet the needs of different users and applications, and can be used with Mapbox's suite of mapping tools to create interactive maps for web and mobile applications. Mapbox styles are based on the Mapbox Style Specification, which is an open-source specification for designing and sharing map styles.
|
||||
|
||||
<div className="ndl-image-with-background">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
## Prebuilt Styles
|
||||
|
||||
Mapbox have a few prebuilt styles, here are a few of them:
|
||||
|
||||
- Streets: A classic style that emphasizes roads, parks, and other features of urban areas.
|
||||
- Outdoors: Designed for outdoor enthusiasts, this style includes topographic lines, hiking trails, and other natural features.
|
||||
- Light: A minimalist style that focuses on the essentials of a map, with a light color scheme that's easy on the eyes.
|
||||
- Dark: A more dramatic version of the Light style, with a dark color scheme that's perfect for nighttime maps.
|
||||
- Satellite: This style uses satellite imagery to show real-world views of the Earth's surface, and is often used for mapping remote areas or monitoring changes in the environment.
|
||||
- Navigation: A style optimized for driving and navigation, with a focus on road networks and landmarks.
|
||||
|
||||
You can find them [here](https://docs.mapbox.com/api/maps/styles/#mapbox-styles). Here is the same list with the styles:
|
||||
|
||||
<div className="ndl-table-35-65">
|
||||
|
||||
| Style | Source |
|
||||
| ----------------- | -------------------------------------------- |
|
||||
| Streets | mapbox://styles/mapbox/streets-v12 |
|
||||
| Outdoors | mapbox://styles/mapbox/outdoors-v12 |
|
||||
| Light | mapbox://styles/mapbox/light-v11 |
|
||||
| Dark | mapbox://styles/mapbox/dark-v11 |
|
||||
| Satellite | mapbox://styles/mapbox/satellite-v9 |
|
||||
| Satellite Streets | mapbox://styles/mapbox/satellite-streets-v12 |
|
||||
| Navigation Day | mapbox://styles/mapbox/navigation-day-v1 |
|
||||
| Navigation Night | mapbox://styles/mapbox/navigation-night-v1 |
|
||||
|
||||
</div>
|
||||
|
||||
## Custom Styles
|
||||
|
||||
You can also use [Mapbox Studio](https://www.mapbox.com/mapbox-studio) to create your own custom styles.
|
||||
|
||||
In Mapbox Studio you will get a link which should be passed into `Style`, and you will have the custom style.
|
||||
|
||||
## Style Object
|
||||
|
||||
Looking at the Mapbox "Add a video" example, which can be [here](https://docs.mapbox.com/mapbox-gl-js/example/video-on-a-map/).
|
||||
|
||||
In this example a Javascript object is used to create the style.
|
||||
|
||||
Here is how we can recreate this example in Noodl.
|
||||
|
||||
1. Create a Function node, with this code:
|
||||
|
||||
```js
|
||||
Outputs.MapStyle = JSON.stringify({
|
||||
version: 8,
|
||||
sources: {
|
||||
satellite: {
|
||||
type: "raster",
|
||||
url: "mapbox://mapbox.satellite",
|
||||
tileSize: 256,
|
||||
},
|
||||
video: {
|
||||
type: "video",
|
||||
urls: [
|
||||
"https://static-assets.mapbox.com/mapbox-gl-js/drone.mp4",
|
||||
"https://static-assets.mapbox.com/mapbox-gl-js/drone.webm",
|
||||
],
|
||||
coordinates: [
|
||||
[-122.51596391201019, 37.56238816766053],
|
||||
[-122.51467645168304, 37.56410183312965],
|
||||
[-122.51309394836426, 37.563391708549425],
|
||||
[-122.51423120498657, 37.56161849366671],
|
||||
],
|
||||
},
|
||||
},
|
||||
layers: [
|
||||
{
|
||||
id: "background",
|
||||
type: "background",
|
||||
paint: {
|
||||
"background-color": "rgb(4,7,14)",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "satellite",
|
||||
type: "raster",
|
||||
source: "satellite",
|
||||
},
|
||||
{
|
||||
id: "video",
|
||||
type: "raster",
|
||||
source: "video",
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
2. Connect the `MapStyle` output to the Mapbox `Style` input. And you will now have the style with a video.
|
||||
|
||||
3. To pause and play the video, like in the example.
|
||||
|
||||
We create another Function node with this code:
|
||||
|
||||
```js
|
||||
const mapboxObject = Inputs.Map;
|
||||
const playOrPause = Inputs.PlayOrPause;
|
||||
|
||||
if (!mapboxObject) return;
|
||||
|
||||
if (playOrPause) {
|
||||
mapboxObject.getSource("video").play();
|
||||
} else {
|
||||
mapboxObject.getSource("video").pause();
|
||||
}
|
||||
```
|
||||
|
||||
And connect it to a Switch node, like in this picture:
|
||||
|
||||
<div className="ndl-image-with-background">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
4. Now we have replicated the example by Mapbox.
|
||||
189
library/modules/mapbox/guides/using-markers/README.md
Normal file
189
library/modules/mapbox/guides/using-markers/README.md
Normal file
@@ -0,0 +1,189 @@
|
||||
---
|
||||
title: Using Markers
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Using Markers in the Mapbox Module
|
||||
|
||||
## What you will learn in this guide
|
||||
|
||||
This guide will teach you how to add and remove markers to your Mapbox Map in Noodl.
|
||||
|
||||
## Overview
|
||||
|
||||
This guide will walk you through the following steps
|
||||
|
||||
- Adding markers to the map
|
||||
- Capturing when the user clicks a marker
|
||||
- Removing markers from the map
|
||||
|
||||
The guide will build on the two previous Mapbox guides, [Setting up Mapbox module](/library/modules/mapbox/guides/setting-up) and [Interacting with the Mapbox Module](/library/modules/mapbox/guides/interacting). It's recommended that you read those guides first.
|
||||
|
||||
## Markers
|
||||
|
||||
Markers are used to mark points in the map. They can be anywhere on the map.
|
||||
|
||||
<div className="ndl-image-with-background s">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
A marker can either be represented by the default icon, or any of the Noodl visual nodes.
|
||||
In this guide we will go with the default icon. The default icon can also have a color of your choice.
|
||||
|
||||
Markers are placed as children to the Mapbox Map node.
|
||||
To change the marker to any of the Noodl visual nodes, just place them as a children in the marker.
|
||||
|
||||
<div className="ndl-image-with-background">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
In our case we would like to create the markers dynamically when you click somewhere on the map.
|
||||
To achieve this we will create a new component that can be used in a Repeater.
|
||||
|
||||
Since this component is going to used in a Repeater, lets also create the Component Inputs node with a few parameters.
|
||||
|
||||
<div className="ndl-image-with-background">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
Next we will create an array that is going to contain the information about each marker.
|
||||
Each [Object](/nodes/data/object/object-node) in the **Array** should be of the format:
|
||||
|
||||
```
|
||||
{
|
||||
"Lat":<the latitude>,
|
||||
"Lon":<the longitude>,
|
||||
"Color":<the color, e.g, "White" or as hex-string "#ffffff". Only used with the default icon.>
|
||||
}
|
||||
```
|
||||
|
||||
So it matches the properties we added in the component.
|
||||
|
||||
First we add an **Array** node. Give it the **id** `Map Markers`.
|
||||
|
||||
<div className="ndl-image-with-background">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
This will feed the markers to a Repeater that is using our new marker component, so connect its output **Items** to the **Markers** input on the **Repeater** node.
|
||||
|
||||
<div className="ndl-image-with-background l">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
Now we need to add new **Objects** to the **Array** whenever the user clicks on the map. Add a [Create New Object](/nodes/data/object/create-new-object) node and make sure you can set the three properties `Lon` (Number), `Lat` (Number) and `Color` (String) when you create it.
|
||||
|
||||
<div className="ndl-image-with-background l">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
<div className="ndl-image-with-background s">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
We want to set the `Lat` and `Lon` to the position the user clicks, so connect the `Latitude` and `Longitude` outputs in the group "Map Clicked" from the Mapbox to the them. We can hard code the color to `Black` for now, so just enter `Black` directly in the properties panel of the **Create New Object** node. Then we connect the **Click** event from the **Mapbox Map** node to the **Do** signal of the **Create New Object** node.
|
||||
|
||||
<div className="ndl-image-with-background l">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
The newly created **Object** need to be added to the **Array** that holds the markers. So by adding a [Insert Object Into Array](/nodes/data/array/insert-into-array) node, connecting the **Done** signal from the **Create new Object Node** to **Do** and also connecting the **Id** to **Object Id** we are almost done. We just need to make sure the insert happens in the correct **Array**. So either hardcode the **Array Id** to `Map Markers`, or connect the **Id** of the **Array** to the **Array Id** of the **Insert Object Into Array** node.
|
||||
|
||||
<div className="ndl-image-with-background l">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
If everything was done correctly, you should now be able to place black markers on the map.
|
||||
|
||||
<div className="ndl-image-with-background">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
## Capturing when the user clicks a marker
|
||||
|
||||
Next step is to be able to do something when the user clicks a marker. So we need to differentiate between clicking on the map and clicking on a marker.
|
||||
|
||||
Conveniently there is an additional outgoing signal on the **Mapbox Marker** node called **Click**.
|
||||
Lets connect the click signal to Component Outputs so we can use it in our main component.
|
||||
|
||||
<div className="ndl-image-with-background l">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
So let's change up the logic slightly, so the panel either shows the marker that was clicked, or the newly created marker if the user didn't click the marker but on the map instead.
|
||||
|
||||
Using [Variable](/nodes/data/variable/variable-node) and [Set Variable](/nodes/data/variable/set-variable) node and some logic around that, we make sure a **Variable** holds the current marker. See the [guide](/docs/guides/data/variables) on using **Variables** if you want to know more about how to use them.
|
||||
Also, the **Marker Click** signal now makes the panel visible as well. The full node design can be seen below.
|
||||
|
||||
<div className="ndl-image-with-background l">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
Finally, let's update the panel logic. We want to make sure the latitude/longitude values comes from the marker and not from where you clicked on the map. It won't make a difference now, but we might want to capture more information in the marker to show in the panel, so this is a better design.
|
||||
|
||||
The `Current Marker` Variable holds the **Id** of the current marker, so just connect it to an **Object** and take out the `Lon` and `Lat` properties from it. The updated design is shown below.
|
||||
|
||||
<div className="ndl-image-with-background l">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
## Removing Markers
|
||||
|
||||
Finally we want to be able to remove markers. It's very easy, just remove them from the Marker **Array**.
|
||||
So let's add a [Button](/nodes/ui-controls/button) to the panel. Remove its label and instead add an icon that represents "delete". Also make it smaller by adapting its padding and size. Finally make it red so it's clear it's a destructive action.
|
||||
|
||||
<div className="ndl-image-with-background s">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
<div className="ndl-image-with-background l">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
<div className="ndl-image-with-background s">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
<div className="ndl-image-with-background">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
We connect the functionality for the button. We add a [Remove Object From Array](/nodes/data/array/remove-from-array) node and make sure the **Object Id** is what's stored in the `Current Marker` **Variable** and the **Array Id** comes the same **Id** as the `Map Markers` **Array**.
|
||||
|
||||
The **Click** signal from the **Button** is connected to **Do** on the **Remove Object From Array** node. Finally we also close the panel when the removal is **Done**.
|
||||
|
||||
This is what the final node construct looks like. If you want to import the final project click the "Import" button:
|
||||
Reference in New Issue
Block a user