Skip to content

Instantly share code, notes, and snippets.

@theronic
Last active June 22, 2023 10:26
Show Gist options
  • Save theronic/5da57a8c41a8904dab61e33beccec459 to your computer and use it in GitHub Desktop.
Save theronic/5da57a8c41a8904dab61e33beccec459 to your computer and use it in GitHub Desktop.
Struggling to port DrawControl React component to Reagent
(ns ui.map
#?(:cljs (:require-macros [ui.map :refer [with-reagent]]))
(:require [hyperfiddle.electric :as e]
[hyperfiddle.electric-dom2 :as dom]
[reagent.core :as r]
#?(:cljs ["react" :as React])
#?(:cljs ["react-dom/client" :as ReactDom])
#?(:cljs ["react-map-gl" :as ReactMapGl])
#?(:cljs ["@mapbox/mapbox-gl-draw" :as MapboxDraw])))
;; Please refer https://github.com/visgl/react-map-gl/blob/master/examples/draw-polygon/src/draw-control.ts
(def MAPBOX_TOKEN "<token goes here>")
#?(:cljs (def ReactRootWrapper
(r/create-class
{:component-did-mount (fn [this] (js/console.log "mounted"))
:render (fn [this]
(let [[_ Component & args] (r/argv this)]
(into [Component] args)))})))
(def react-root-hook "See `e/with`"
#?(:clj dom/unsupported
:cljs (fn ([x] (.unmount x))
([x y] (.insertBefore (.-parentNode x) x y)))))
#?(:cljs (defn create-root
"See https://reactjs.org/docs/react-dom-client.html#createroot"
([node] (create-root node (str (gensym))))
([node id-prefix]
(ReactDom/createRoot node #js {:identifierPrefix id-prefix}))))
#?(:cljs (defn render [root & args]
(.render root (r/as-element (into [ReactRootWrapper] args)))))
#?(:cljs
(defn draw-control [^js props]
(let [position (.-position props)
onCreate (.-onCreate props)
onUpdate (.-onUpdate props)
onDelete (.-onDelete props)]
(ReactMapGl/useControl
(MapboxDraw. props)
(fn [{:as args :keys [map]}]
(.on map "draw.create" onCreate)
(.on map "draw.update" onUpdate)
(.on map "draw.delete" onDelete))
(fn [{:keys [map]}]
(.off map "draw.create" onCreate)
(.off map "draw.update" onUpdate)
(.off map "draw.delete" onDelete))
#js {:position position}))
; do we need to return null here?
nil))
#?(:cljs
(defn MyMap []
(let [on-update (React/useCallback
(fn [e]
;; todo setFeatures here.
(prn "onupdate" e)
nil)
(to-array []))]
[:> ReactMapGl/Map {:style {:width "100vw"
:height "100vh"}
:mapboxAccessToken MAPBOX_TOKEN
:initialViewState {:longitude -91.874
:latitude 42.76
:zoom 12}
:mapStyle "mapbox://styles/mapbox/light-v9"}
[:> draw-control
{:position "top-left"
:displayControlsDefault false
:controls {:polygon true, :trash true}
:defaultMode "draw_polygon"
:onCreate on-update
:onUpdate on-update
:onDelete on-update}]])))
(defmacro with-reagent [& args]
`(dom/div ; React will hijack this element and empty it.
(binding [dom/node (create-root dom/node)]
(new (e/hook react-root-hook dom/node
(e/fn [] dom/keepalive
(render dom/node ~@args)))))))
(e/defn App []
(e/client
(dom/link (dom/props {:rel :stylesheet :href "/olarm.css"}))
(dom/div
(with-reagent MyMap))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment