Flying with F#
Tags: fsharp, fable
Published: 2023-12-09 15:54:33

This blog post is a part of the awesome [F# Advent Calendar in English](https://sergeytihon.com/2023/10/28/f-advent-calendar-in-english-2023/) organized by Sergey Tihon, an annual collection of more than 30 posts, that could form a book "F# in Practice" by the community.

The source code for the presented experiments can be found [here](https://github.com/PawelStadnicki/flying-with-fsharp).

**The topic**

How far are F# devs from creating sth cool?

> Sometimes it is just a single JS binding. 

In my spare time, I enjoy working on Proof of Concept (POC) projects.

I select something that I find interesting, quickly develop a Proof of Concept, and then move on to the next one.

I believe that by creating around 20 POCs, I can eventually build an interesting product from a few of them. It's a reverse approach to applying technology. Normally, you start with a specific need that technology should address, but in my case, I begin with the technology itself.

Certainly, this approach may not be the most conventional or lucrative one, but I find it rewarding nonetheless.

This time I present how to combine F# with Google 3D Photorealistic tiles.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p1f6oruazd1uhp34nlts.gif)

I demonstrate the seamless integration of key elements. With each animation frame, you can harness values like location, bearing, zoom, and pitch, and transform these into captivating experiences - from rotating around a locale to following a route, or even simulating a drone flight. Elevate your website with a map that's not just dynamic but truly alive!

Start by obtaining your [own API key](https://developers.google.com/maps/documentation/tile/get-api-key) for the 3D tiles. While this product has transitioned from a preview to a paid service, you can receive a generous $200 monthly credit, giving you ample freedom to explore its features. Beyond this, the cost is $6 per 1,000 'root requests'. For high-traffic applications, this means $6,000 for every million views. It's important to factor this into your planning. For more details, be sure to review the documentation thoroughly.


**Implementation**

The best thing about tiles in general is that all you need is to host them and move around with some sort of engine. Obviously, all of these engines are inherently connected to JavaScript. Fortunately, we have Fable, so the only challenge is to find a library, for each we can write binding easily.

I noticed on Twitter that [Foursquare Studio](https://studio.foursquare.com/home) has the option to add these tiles very easily:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4srxv36kg4t6rkbnwrz9.png)

I knew that this tool is built with DeckGL, so I checked their docs and ... there is a very simple example (https://deck.gl/examples/google-3d-tiles). 

Translation of this example to Fable looks like (one of the possible approaches):

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/plcb3q5evioua7kb1kq2.png)
And the actual binding:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7962qwthp1fdiho0h4h9.png)

DeckGL just expects view state object with certain values to be used in the projection (and animations):
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iu8yi2g4c66gcyptv6z8.png)

As we are using React, all we have to do is update this object with the setState or Elmish hook. In my experiments, I'm using the latter.

The PoC has a simple dashboard, you can check the implementation to see how appropriate values are updated with Elmish style:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lne6jk182ou8eq7b29a1.png)

I also provided 4 simple animations:
- move to a location:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tk0edolrd834isibt1ri.gif)

- rotate 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hngwnt6s3u6t8nioouxm.gif)

Implementation of the rotation move is pretty straightforward:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/90fswf304gb7yola12de.png)

- follow the path 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sdwofpy3yl4o15s7p8zb.gif)

Implementation is slightly more complicated:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/69x0nc5pc1r24a12gvzg.png)

You can notice a pattern that in order to create new animation you only have to implement a function and describe how the view (state) changes with time:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/27irbdjsyxs1kzjlyw1m.png)

Calling such animations in Elmish requires returning it as a Cmd of effect: 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eq57j7p7v2yewvshy3rd.png)

Other interesting animations can come from the keyboard events: 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m4x2zxaap6qiz3af4rtt.png)

Check the implementation if you are interested in how I played to emulate a drone flight. Make note that it is a very naive and not complete approach. Actually, this is not the way it should be done: instead, some sort of DeckGL view should be created. However, I had fun with it and could completely control the animation.

Few more suggestions:
- to get the user location (from the browser):

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rwnw35x519pcoa3m23l7.png)

- to measure distances and convert between our parameters I'm using [TurfJS](https://turfjs.org/), for which binding is even more trivial:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4e3puj0228f2tzxqx82p.png)

**Summary:**
This is a brief description of my 3D tiles endeavor. We can go pretty far with it. If you are interested in moving it further or using it in your project, please reach out to me via [Twitter](https://twitter.com/florence_dev).