8.6 KiB
Embedding maps in your apps
Introduction
Below you will find some simple examples of using map api's inside clojure, you can use the inline eval for some of the example where sci supports a specific library. Install npm dependencies
Setup for downloaded version
Install the npm dependencies for react then launch shadow via the terminal or jack in via your IDE.
Google Maps
Below is an example of using google maps, it pulls in the library directly you could alternatively use an npm dependency.
You will need to provide your own api key, the examples are blank and render a warning so paste in your google api key to make this work.
Load in the google maps script by adding it to the dom
Code pulled from google
(defn load-google-maps-script [api-key]
(let [script (.createElement js/document "script")]
;; copied from googles recommended way of loading google maps
(set! (.-innerHTML script) (str "(g=>{var h,a,k,p=\"The Google Maps JavaScript API\",c=\"google\",l=\"importLibrary\",q=\"__ib__\",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement(\"script\"));e.set(\"libraries\",[...r]+\"\");for(k in g)e.set(k.replace(/[A-Z]/g,t=>\"_\"+t[0].toLowerCase()),g[k]);e.set(\"callback\",c+\".maps.\"+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+\" could not load.\"));a.nonce=m.querySelector(\"script[nonce]\")?.nonce||\"\";m.head.append(a)}));d[l]?console.warn(p+\" only loads once. Ignoring:\",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({
key: \"" api-key "\", v: \"weekly\"});"))
(.appendChild (.-head js/document) script)))
Create a map using google and core async
In this example we render google maps using core async, async go blocks drop type hints so we need to pull out any hinting to functions, this is a shame as this version reduces the amount of nesting.
(defn google-map-core-async []
(let [map-element (reagent/atom nil)
;; pulled out of the go block to satisfy the infer warnings, the go block removes hints
get-map-obj (fn [obj] (.-Map ^js/google.maps.Map obj))
get-marker-obj (fn [obj] (.-Marker ^js/google.maps.Map obj))]
(load-google-maps-script "")
;; go blocks loose hints so may cause infer warnings
(async/go (let [gMap (get-map-obj (async-in/<p! (js/google.maps.importLibrary "maps")))
gMarker (get-marker-obj (async-in/<p! (js/google.maps.importLibrary "marker")))
map (gMap. @map-element
(clj->js {:center {:lng 131.031 :lat -25.344} :zoom 4}))]
(gMarker. (clj->js {:map map
:title "test marker 1"
:position {:lng 131.031 :lat -24.344}}) "marker 1")
(gMarker. (clj->js {:map map
:title "test marker 2"
:position {:lng 131.031 :lat -25.344}}) "marker 2")))
(fn []
[:div#google-map-async.m-4
{:style {:width "400px" :height "400px"} :ref #(reset! map-element %)}
"core async map here"])))
Create a map using google and shadow js-await
(defn google-map-js-await []
(let [map-element (reagent/atom nil)]
(load-google-maps-script "")
(shadow/js-await
[js-map (js/google.maps.importLibrary "maps")]
(shadow/js-await
[js-marker (js/google.maps.importLibrary "marker")]
(when @map-element
(let [gMap (.-Map ^js/google.maps.Map js-map)
gMarker (.-Marker ^js/google.maps.Marker js-marker)
map (gMap. @map-element
(clj->js {:center {:lng 131.031 :lat -25.344} :zoom 4}))]
(gMarker. (clj->js {:map map
:title "test marker 1"
:position {:lng 131.031 :lat -24.344}}) "marker 1")
(gMarker. (clj->js {:map map
:title "test marker 2"
:position {:lng 131.031 :lat -25.344}}) "marker 2")
nil))))
(fn []
[:div#google-map-js-await.m-4
{:style {:width "400px" :height "400px"} :ref #(reset! map-element %)}
"shadow js-await map here"])))
[google-map-js-await]
Create a map using google and promesa
An example using promesa to render a google map.
(defn google-map-promesa []
(let [map-element (reagent/atom nil)]
(load-google-maps-script "")
(promesa/let
[js-map (js/google.maps.importLibrary "maps")
js-marker (js/google.maps.importLibrary "marker")]
(let
[gMap (.-Map ^js/google.maps.Map js-map)
gMarker (.-Marker ^js/google.maps.Marker js-marker)
map (gMap. @map-element
(clj->js {:center {:lng 131.031 :lat -25.344} :zoom 4}))]
(gMarker. (clj->js {:map map
:title "test"
:position {:lng 131.031 :lat -24.344}}) "marker 1")
(gMarker. (clj->js {:map map
:title "test"
:position {:lng 131.031 :lat -25.344}}) "marker 1")))
(fn []
[:div#google-map-promesa.m-4
{:style {:width "400px" :height "400px"} :ref #(reset! map-element %)}
"promesa map here"])))
[google-map-promesa]