From f4ab3e17ad5732a5589e17ad5c0991ab14164902 Mon Sep 17 00:00:00 2001 From: zapashcanon Date: Fri, 8 Apr 2022 22:43:31 +0200 Subject: [PATCH 01/43] use gadts for event, clean repo --- src/dune | 14 +++++++-- src/ev.ml | 31 -------------------- src/ev.mli | 66 ------------------------------------------ src/event.ml | 59 +++++++++++++++++++++++++++++++++++++ src/event.mli | 42 +++++++++++++++++++++++++++ src/leaflet.js.license | 3 -- src/map.ml | 18 ++++-------- src/map.mli | 11 +------ 8 files changed, 118 insertions(+), 126 deletions(-) delete mode 100644 src/ev.ml delete mode 100644 src/ev.mli create mode 100644 src/event.ml create mode 100644 src/event.mli delete mode 100644 src/leaflet.js.license diff --git a/src/dune b/src/dune index 8f28969..bce2f76 100644 --- a/src/dune +++ b/src/dune @@ -1,7 +1,15 @@ (library - (name leaflet) (public_name leaflet) - (modules ev latlng geojson_layer tile_layer popup marker map global layer) - (libraries brr js_of_ocaml) + (modules + event + geojson_layer + global + latlng + layer + map + marker + popup + tile_layer) + (libraries brr) (js_of_ocaml (javascript_files leaflet.js))) diff --git a/src/ev.ml b/src/ev.ml deleted file mode 100644 index 7823351..0000000 --- a/src/ev.ml +++ /dev/null @@ -1,31 +0,0 @@ -module Make () = struct - type t = Jv.t - - let type' e = Jv.get e "type" |> Jv.to_string - - let target e = Jv.get e "target" |> Brr.Ev.target_of_jv - - let source_target e = Jv.get e "sourceTarget" |> Brr.Ev.target_of_jv - - let propagated_from e = Jv.get e "propagatedFrom" - - let latlng e = Latlng.of_jv_t @@ Jv.get e "latlng" - - let layer_point e = Jv.get e "layerPoint" - - let container_point e = Jv.get e "containerPoint" - - let original_event e = Jv.get e "originalEvent" - - let message e = Jv.get e "message" |> Jv.to_string - - let code e = Jv.get e "code" |> Jv.to_int -end - -module Event = Make () - -module Keyboard = Make () - -module Mouse = Make () - -module Error = Make () diff --git a/src/ev.mli b/src/ev.mli deleted file mode 100644 index 520b5ff..0000000 --- a/src/ev.mli +++ /dev/null @@ -1,66 +0,0 @@ -module Event : sig - type t - - val type' : t -> string - - val target : t -> Brr.Ev.target - - val source_target : t -> Brr.Ev.target - - (* TODO this should return Point *) - val propagated_from : t -> Jv.t -end - -module Keyboard : sig - type t - - val type' : t -> string - - val target : t -> Brr.Ev.target - - val source_target : t -> Brr.Ev.target - - val propagated_from : t -> Jv.t - - (* TODO this should return BrrDomEvent*) - val original_event : t -> Jv.t -end - -module Mouse : sig - type t - - val type' : t -> string - - val target : t -> Brr.Ev.target - - val source_target : t -> Brr.Ev.target - - val propagated_from : t -> Jv.t - - val latlng : t -> Latlng.t - - (* TODO this should return Point *) - val layer_point : t -> Jv.t - - (* TODO this should return Point *) - val container_point : t -> Jv.t - - (* TODO this should return BrrDomEvent*) - val original_event : t -> Jv.t -end - -module Error : sig - type t - - val type' : t -> string - - val target : t -> Brr.Ev.target - - val source_target : t -> Brr.Ev.target - - val propagated_from : t -> Jv.t - - val message : t -> string - - val code : t -> int -end diff --git a/src/event.ml b/src/event.ml new file mode 100644 index 0000000..491f322 --- /dev/null +++ b/src/event.ml @@ -0,0 +1,59 @@ +type _ t = + | Keyboard : Jv.t -> [> `Keyboard ] t + | Mouse : Jv.t -> [> `Mouse ] t + | Error : Jv.t -> [> `Error ] t + | Basic : Jv.t -> [> `Basic ] t + +type _ sub = + | Click : [> `Mouse ] sub + | Move_end : [> `Basic ] sub + | Zoom_end : [> `Basic ] sub + +let of_jv_t : type kind. kind sub -> Jv.t -> kind t = + fun tag e -> + match tag with Click -> Mouse e | Move_end -> Basic e | Zoom_end -> Basic e + +let sub_to_string : type kind. kind sub -> string = function + | Click -> "click" + | Move_end -> "moveend" + | Zoom_end -> "zoomend" + +(** Basic events *) + +let get_type : type kind. kind t -> string = function + | Keyboard e | Mouse e | Error e | Basic e -> Jv.get e "type" |> Jv.to_string + +let target : type kind. kind t -> Brr.Ev.target = function + | Keyboard e | Mouse e | Error e | Basic e -> + Jv.get e "target" |> Brr.Ev.target_of_jv + +let source_target : type kind. kind t -> Brr.Ev.target = function + | Keyboard e | Mouse e | Error e | Basic e -> + Jv.get e "sourceTarget" |> Brr.Ev.target_of_jv + +let propagated_from : type kind. kind t -> Jv.t = function + | Keyboard e | Mouse e | Error e | Basic e -> Jv.get e "propagatedFrom" + +(** Keyboard & Mouse events *) + +let original_event : [ `Keyboard | `Mouse ] t -> Jv.t = function + | Keyboard e | Mouse e -> Jv.get e "originalEvent" + +(** Mouse events *) + +let container_point : [ `Mouse ] t -> Jv.t = function + | Mouse e -> Jv.get e "containerPoint" + +let layer_point : [ `Mouse ] t -> Jv.t = function + | Mouse e -> Jv.get e "layerPoint" + +let latlng : [ `Mouse ] t -> Latlng.t = function + | Mouse e -> Jv.get e "latlng" |> Latlng.of_jv_t + +(** Error events *) + +let code : [ `Error ] t -> int = function + | Error e -> Jv.get e "code" |> Jv.to_int + +let message : [ `Error ] t -> string = function + | Error e -> Jv.get e "message" |> Jv.to_string diff --git a/src/event.mli b/src/event.mli new file mode 100644 index 0000000..bf4f2d7 --- /dev/null +++ b/src/event.mli @@ -0,0 +1,42 @@ +type _ t = + | Keyboard : Jv.t -> [> `Keyboard ] t + | Mouse : Jv.t -> [> `Mouse ] t + | Error : Jv.t -> [> `Error ] t + | Basic : Jv.t -> [> `Basic ] t + +type _ sub = + | Click : [> `Mouse ] sub + | Move_end : [> `Basic ] sub + | Zoom_end : [> `Basic ] sub + +val of_jv_t : 'a sub -> Jv.t -> 'a t + +val sub_to_string : _ sub -> string + +(** Basic events *) + +val get_type : _ t -> string + +val target : _ t -> Brr.Ev.target + +val source_target : _ t -> Brr.Ev.target + +val propagated_from : _ t -> Jv.t + +(** Keyboard & Mouse events *) + +val original_event : [ `Keyboard | `Mouse ] t -> Jv.t + +(** Mouse events *) + +val container_point : [ `Mouse ] t -> Jv.t + +val layer_point : [ `Mouse ] t -> Jv.t + +val latlng : [ `Mouse ] t -> Latlng.t + +(** Error events *) + +val code : [ `Error ] t -> int + +val message : [ `Error ] t -> string diff --git a/src/leaflet.js.license b/src/leaflet.js.license deleted file mode 100644 index 8f54aad..0000000 --- a/src/leaflet.js.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2010-2021 Vladimir Agafonkin - -SPDX-License-Identifier: BSD-2-Clause \ No newline at end of file diff --git a/src/map.ml b/src/map.ml index 3efedd7..e070351 100644 --- a/src/map.ml +++ b/src/map.ml @@ -1,15 +1,5 @@ type t = Jv.t -module Event = struct - let to_brr s = s |> Jstr.v |> Brr.Ev.Type.create - - let click = to_brr "click" - - let moveend = to_brr "moveend" - - let zoomend = to_brr "zoomend" -end - let of_jv_t = Fun.id let to_jv_t = Fun.id @@ -34,9 +24,11 @@ let set_view latlng ?zoom map = let as_target map = Brr.Ev.target_of_jv map -let on ~event ~handler map = - let name = Brr.Ev.Type.name event |> Jv.of_jstr in - ignore @@ Jv.call map "on" [| name; Jv.repr handler |] +let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> t -> unit = + fun event handler map -> + let name = Event.sub_to_string event in + let handler v = handler @@ Event.of_jv_t event v in + ignore @@ Jv.call map "on" [| Jv.of_string name; Jv.repr handler |] let get_center map = Latlng.of_jv_t @@ Jv.call map "getCenter" [||] diff --git a/src/map.mli b/src/map.mli index c373001..fdbd710 100644 --- a/src/map.mli +++ b/src/map.mli @@ -1,14 +1,5 @@ type t -module Event : sig - (* TODO do this need to be wrapped in Brr.Ev.type' ?*) - val click : Ev.Mouse.t Brr.Ev.type' - - val moveend : Ev.Event.t Brr.Ev.type' - - val zoomend : Ev.Event.t Brr.Ev.type' -end - val create : ?options:Jv.t -> string -> t val invalidate_size : t -> unit @@ -19,7 +10,7 @@ val fit_world : t -> unit val get_container : t -> Brr.El.t -val on : event:'a Brr.Ev.type' -> handler:('a -> 'b) -> t -> unit +val on : 'a Event.sub -> ('a Event.t -> 'b) -> t -> unit val get_center : t -> Latlng.t From fbfb4037344214e6752dbdde5e168a124d46e265 Mon Sep 17 00:00:00 2001 From: zapashcanon Date: Sat, 9 Apr 2022 22:21:22 +0200 Subject: [PATCH 02/43] use gadts for layer, clean code --- src/dune | 12 +----- src/event.ml | 4 +- src/event.mli | 2 +- src/geojson_layer.ml | 4 -- src/geojson_layer.mli | 23 ----------- src/latlng.ml | 4 +- src/latlng.mli | 4 +- src/layer.ml | 92 +++++++++++++++++++++++++++++++++++++------ src/layer.mli | 38 ++++++++++++------ src/map.ml | 39 ++++++++++-------- src/map.mli | 6 +-- src/marker.ml | 4 -- src/marker.mli | 23 ----------- src/popup.ml | 16 +++++--- src/popup.mli | 2 +- src/tile_layer.ml | 19 --------- src/tile_layer.mli | 23 ----------- 17 files changed, 152 insertions(+), 163 deletions(-) delete mode 100644 src/geojson_layer.ml delete mode 100644 src/geojson_layer.mli delete mode 100644 src/marker.ml delete mode 100644 src/marker.mli delete mode 100644 src/tile_layer.ml delete mode 100644 src/tile_layer.mli diff --git a/src/dune b/src/dune index bce2f76..ed4515f 100644 --- a/src/dune +++ b/src/dune @@ -1,15 +1,7 @@ (library (public_name leaflet) - (modules - event - geojson_layer - global - latlng - layer - map - marker - popup - tile_layer) + (modules event global latlng layer map popup) + (private_modules global) (libraries brr) (js_of_ocaml (javascript_files leaflet.js))) diff --git a/src/event.ml b/src/event.ml index 491f322..6b456d2 100644 --- a/src/event.ml +++ b/src/event.ml @@ -9,7 +9,7 @@ type _ sub = | Move_end : [> `Basic ] sub | Zoom_end : [> `Basic ] sub -let of_jv_t : type kind. kind sub -> Jv.t -> kind t = +let of_jv : type kind. kind sub -> Jv.t -> kind t = fun tag e -> match tag with Click -> Mouse e | Move_end -> Basic e | Zoom_end -> Basic e @@ -48,7 +48,7 @@ let layer_point : [ `Mouse ] t -> Jv.t = function | Mouse e -> Jv.get e "layerPoint" let latlng : [ `Mouse ] t -> Latlng.t = function - | Mouse e -> Jv.get e "latlng" |> Latlng.of_jv_t + | Mouse e -> Jv.get e "latlng" |> Latlng.of_jv (** Error events *) diff --git a/src/event.mli b/src/event.mli index bf4f2d7..9592bfb 100644 --- a/src/event.mli +++ b/src/event.mli @@ -9,7 +9,7 @@ type _ sub = | Move_end : [> `Basic ] sub | Zoom_end : [> `Basic ] sub -val of_jv_t : 'a sub -> Jv.t -> 'a t +val of_jv : 'a sub -> Jv.t -> 'a t val sub_to_string : _ sub -> string diff --git a/src/geojson_layer.ml b/src/geojson_layer.ml deleted file mode 100644 index c5c113d..0000000 --- a/src/geojson_layer.ml +++ /dev/null @@ -1,4 +0,0 @@ -include Layer - -let create ?(options = Jv.null) geojson = - of_jv_t @@ Jv.call Global.leaflet "geoJSON" [| geojson; options |] diff --git a/src/geojson_layer.mli b/src/geojson_layer.mli deleted file mode 100644 index e8c4660..0000000 --- a/src/geojson_layer.mli +++ /dev/null @@ -1,23 +0,0 @@ -type t - -val create : ?options:Jv.t -> Jv.t -> t - -val add_to : Map.t -> t -> unit - -val remove : t -> unit - -val remove_from : Map.t -> t -> unit - -val bind_popup : Brr.El.t -> t -> unit - -val unbind_popup : t -> unit - -val open_popup : t -> unit - -val close_popup : t -> unit - -val get_popup : t -> Popup.t - -val of_jv_t : Jv.t -> t - -val to_jv_t : t -> Jv.t diff --git a/src/latlng.ml b/src/latlng.ml index d2b4dbc..6611746 100644 --- a/src/latlng.ml +++ b/src/latlng.ml @@ -9,6 +9,6 @@ let lng latlng = Jv.get latlng "lng" |> Jv.to_float let equals a b = Jv.call a "equals" [| b |] |> Jv.to_bool -let of_jv_t = Fun.id +let of_jv = Fun.id -let to_jv_t = Fun.id +let to_jv = Fun.id diff --git a/src/latlng.mli b/src/latlng.mli index fb793ae..c63a970 100644 --- a/src/latlng.mli +++ b/src/latlng.mli @@ -8,6 +8,6 @@ val lng : t -> float val equals : t -> t -> bool -val of_jv_t : Jv.t -> t +val of_jv : Jv.t -> t -val to_jv_t : t -> Jv.t +val to_jv : t -> Jv.t diff --git a/src/layer.ml b/src/layer.ml index d0c8b62..fd9b07a 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -1,23 +1,89 @@ -type t = Jv.t +type _ t = + | Basic : Jv.t -> [> `Basic ] t + | Geojson : Jv.t -> [> `Geojson ] t + | Marker : Jv.t -> [> `Marker ] t + | Tile : Jv.t -> [> `Tile ] t -let add_to map layer = ignore @@ Jv.call layer "addTo" [| Map.to_jv_t map |] +(** Basic layers *) -let remove layer = ignore @@ Jv.call layer "remove" [||] +let add_to : type kind. Map.t -> kind t -> unit = + fun map -> function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "addTo" [| Map.to_jv map |] in + () -let remove_from map layer = - ignore @@ Jv.call layer "removeFrom" [| Map.to_jv_t map |] +let remove : type kind. kind t -> unit = function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "remove" [||] in + () -let bind_popup el layer = - ignore @@ Jv.call layer "bindPopup" [| Brr.El.to_jv el |] +let remove_from : type kind. Map.t -> kind t -> unit = + fun map -> function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "removeFrom" [| Map.to_jv map |] in + () -let unbind_popup layer = ignore @@ Jv.call layer "unbindPopup" [||] +let bind_popup : type kind. Brr.El.t -> kind t -> unit = + fun el -> function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "bindPopup" [| Brr.El.to_jv el |] in + () -let open_popup layer = ignore @@ Jv.call layer "openPopup" [||] +let unbind_popup : type kind. kind t -> unit = function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "unbindPopup" [||] in + () -let close_popup layer = ignore @@ Jv.call layer "closePopup" [||] +let open_popup : type kind. kind t -> unit = function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "openPopup" [||] in + () -let get_popup layer = Popup.of_jv_t @@ Jv.call layer "getPopup" [||] +let close_popup : type kind. kind t -> unit = function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "closePopup" [||] in + () -let of_jv_t = Fun.id +let get_popup : type kind. kind t -> Popup.t = function + | Basic l | Geojson l | Marker l | Tile l -> + Jv.call l "getPopup" [||] |> Popup.of_jv -let to_jv_t = Fun.id +let to_jv : type kind. kind t -> Jv.t = function + | Basic l | Geojson l | Marker l | Tile l -> l + +(** Geojson layers *) + +let create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t = + fun ?(options = Jv.null) geojson -> + let jv_t = Jv.call Global.leaflet "geoJSON" [| geojson; options |] in + Geojson jv_t + +(** Marker layers *) + +let create_marker : Latlng.t -> [ `Marker ] t = + fun latlng -> + let jv_t = Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng |] in + Marker jv_t + +(** Tile layers *) + +let create_tile_osm : string option -> [ `Tile ] t = + fun url -> + (* see https://wiki.openstreetmap.org/wiki/Tile_servers *) + let url = + Option.value url + ~default:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" + in + let jv_t = + Jv.call Global.leaflet "tileLayer" + [| Jv.of_string url + ; Jv.obj + [| ( "attribution" + , Jv.of_string + "© OpenStreetMap \ + contributors" ) + |] + |] + in + Tile jv_t diff --git a/src/layer.mli b/src/layer.mli index 98fe10c..0baf3fd 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -1,21 +1,37 @@ -type t +type _ t = + | Basic : Jv.t -> [> `Basic ] t + | Geojson : Jv.t -> [> `Geojson ] t + | Marker : Jv.t -> [> `Marker ] t + | Tile : Jv.t -> [> `Tile ] t -val add_to : Map.t -> t -> unit +(** Basic layers *) -val remove : t -> unit +val add_to : Map.t -> _ t -> unit -val remove_from : Map.t -> t -> unit +val remove : _ t -> unit -val bind_popup : Brr.El.t -> t -> unit +val remove_from : Map.t -> _ t -> unit -val unbind_popup : t -> unit +val bind_popup : Brr.El.t -> _ t -> unit -val open_popup : t -> unit +val unbind_popup : _ t -> unit -val close_popup : t -> unit +val open_popup : _ t -> unit -val get_popup : t -> Popup.t +val close_popup : _ t -> unit -val of_jv_t : Jv.t -> t +val get_popup : _ t -> Popup.t -val to_jv_t : t -> Jv.t +val to_jv : _ t -> Jv.t + +(** Geojson layers *) + +val create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t + +(** Marker layers *) + +val create_marker : Latlng.t -> [ `Marker ] t + +(** Tile layers *) + +val create_tile_osm : string option -> [ `Tile ] t diff --git a/src/map.ml b/src/map.ml index e070351..57598f4 100644 --- a/src/map.ml +++ b/src/map.ml @@ -1,38 +1,43 @@ type t = Jv.t -let of_jv_t = Fun.id +let of_jv = Fun.id -let to_jv_t = Fun.id +let to_jv = Fun.id let create ?(options = Jv.null) container_id = Jv.call Global.leaflet "map" [| Jv.of_string container_id; options |] -let invalidate_size map = ignore @@ Jv.call map "invalidateSize" [| Jv.true' |] +let invalidate_size map = + let (_ : Jv.t) = Jv.call map "invalidateSize" [| Jv.true' |] in + () -let fit_world map = ignore @@ Jv.call map "fitWorld" [||] +let fit_world map = + let (_ : Jv.t) = Jv.call map "fitWorld" [||] in + () -let get_container map = - Jv.call (to_jv_t map) "getContainer" [||] |> Brr.El.of_jv +let get_container map = Jv.call (to_jv map) "getContainer" [||] |> Brr.El.of_jv -let set_view latlng ?zoom map = - let latlng = Latlng.to_jv_t latlng in - ignore - @@ - match zoom with - | None -> Jv.call map "setView" [| latlng |] - | Some zoom -> Jv.call map "setView" [| latlng; Jv.of_int zoom |] +let set_view latlng ~zoom map = + let latlng = Latlng.to_jv latlng in + let (_ : Jv.t) = + match zoom with + | None -> Jv.call map "setView" [| latlng |] + | Some zoom -> Jv.call map "setView" [| latlng; Jv.of_int zoom |] + in + () let as_target map = Brr.Ev.target_of_jv map let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> t -> unit = fun event handler map -> let name = Event.sub_to_string event in - let handler v = handler @@ Event.of_jv_t event v in - ignore @@ Jv.call map "on" [| Jv.of_string name; Jv.repr handler |] + let handler v = handler @@ Event.of_jv event v in + let (_ : Jv.t) = Jv.call map "on" [| Jv.of_string name; Jv.repr handler |] in + () -let get_center map = Latlng.of_jv_t @@ Jv.call map "getCenter" [||] +let get_center map = Latlng.of_jv @@ Jv.call map "getCenter" [||] let get_zoom map = Jv.call map "getZoom" [||] |> Jv.to_int let wrapped_latlng latlng map = - Latlng.of_jv_t @@ Jv.call map "wrapLatLng" [| Latlng.to_jv_t latlng |] + Latlng.of_jv @@ Jv.call map "wrapLatLng" [| Latlng.to_jv latlng |] diff --git a/src/map.mli b/src/map.mli index fdbd710..f4f6f2b 100644 --- a/src/map.mli +++ b/src/map.mli @@ -4,7 +4,7 @@ val create : ?options:Jv.t -> string -> t val invalidate_size : t -> unit -val set_view : Latlng.t -> ?zoom:int -> t -> unit +val set_view : Latlng.t -> zoom:int option -> t -> unit val fit_world : t -> unit @@ -20,6 +20,6 @@ val wrapped_latlng : Latlng.t -> t -> Latlng.t val as_target : t -> Brr.Ev.target -val of_jv_t : Jv.t -> t +val of_jv : Jv.t -> t -val to_jv_t : t -> Jv.t +val to_jv : t -> Jv.t diff --git a/src/marker.ml b/src/marker.ml deleted file mode 100644 index 44925a1..0000000 --- a/src/marker.ml +++ /dev/null @@ -1,4 +0,0 @@ -include Layer - -let create latlng = - of_jv_t @@ Jv.call Global.leaflet "marker" [| Latlng.to_jv_t latlng |] diff --git a/src/marker.mli b/src/marker.mli deleted file mode 100644 index ab77fc5..0000000 --- a/src/marker.mli +++ /dev/null @@ -1,23 +0,0 @@ -type t - -val create : Latlng.t -> t - -val add_to : Map.t -> t -> unit - -val remove : t -> unit - -val remove_from : Map.t -> t -> unit - -val bind_popup : Brr.El.t -> t -> unit - -val unbind_popup : t -> unit - -val open_popup : t -> unit - -val close_popup : t -> unit - -val get_popup : t -> Popup.t - -val of_jv_t : Jv.t -> t - -val to_jv_t : t -> Jv.t diff --git a/src/popup.ml b/src/popup.ml index bc0febf..fb0264c 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -3,13 +3,19 @@ type t = Jv.t let popup = Jv.call Global.leaflet "popup" [||] let set_latlng latlng = - ignore @@ Jv.call popup "setLatLng" [| Latlng.to_jv_t latlng |] + let (_ : Jv.t) = Jv.call popup "setLatLng" [| Latlng.to_jv latlng |] in + () let set_content content = - ignore @@ Jv.call popup "setContent" [| Jv.of_string content |] + let (_ : Jv.t) = Jv.call popup "setContent" [| Jv.of_string content |] in + () -let open_on map = ignore @@ Jv.call popup "openOn" [| Map.to_jv_t map |] +let open_on map = + let (_ : Jv.t) = Jv.call popup "openOn" [| Map.to_jv map |] in + () -let close map = ignore @@ Jv.call (Map.to_jv_t map) "closePopup" [||] +let close map = + let (_ : Jv.t) = Jv.call (Map.to_jv map) "closePopup" [||] in + () -let of_jv_t = Fun.id +let of_jv = Fun.id diff --git a/src/popup.mli b/src/popup.mli index 5ca939b..65e5dfc 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -8,4 +8,4 @@ val open_on : Map.t -> unit val close : Map.t -> unit -val of_jv_t : Jv.t -> t +val of_jv : Jv.t -> t diff --git a/src/tile_layer.ml b/src/tile_layer.ml deleted file mode 100644 index 1dae48c..0000000 --- a/src/tile_layer.ml +++ /dev/null @@ -1,19 +0,0 @@ -include Layer - -let create_osm ?tile_url () = - (* see https://wiki.openstreetmap.org/wiki/Tile_servers *) - let tile_url = - Option.fold ~some:Fun.id - ~none:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" tile_url - in - of_jv_t - @@ Jv.call Global.leaflet "tileLayer" - [| Jv.of_string tile_url - ; Jv.obj - [| ( "attribution" - , Jv.of_string - "© OpenStreetMap \ - contributors" ) - |] - |] diff --git a/src/tile_layer.mli b/src/tile_layer.mli deleted file mode 100644 index b1834b5..0000000 --- a/src/tile_layer.mli +++ /dev/null @@ -1,23 +0,0 @@ -type t - -val create_osm : ?tile_url:string -> unit -> t - -val add_to : Map.t -> t -> unit - -val remove : t -> unit - -val remove_from : Map.t -> t -> unit - -val bind_popup : Brr.El.t -> t -> unit - -val unbind_popup : t -> unit - -val open_popup : t -> unit - -val close_popup : t -> unit - -val get_popup : t -> Popup.t - -val of_jv_t : Jv.t -> t - -val to_jv_t : t -> Jv.t From a0dc553c7dc8eb3420e372788c9fbb0239528eac Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 12 Apr 2022 13:46:37 +0200 Subject: [PATCH 03/43] license --- LICENSE.md | 11 ++++++----- README.md | 7 +++++-- dune-project | 18 +++++++++--------- leaflet.opam | 23 ++++++++++++++--------- src/event.ml | 2 ++ src/event.mli | 2 ++ src/global.ml | 2 ++ src/latlng.ml | 2 ++ src/latlng.mli | 2 ++ src/layer.ml | 2 ++ src/layer.mli | 2 ++ src/map.ml | 2 ++ src/map.mli | 2 ++ src/popup.ml | 2 ++ src/popup.mli | 2 ++ 15 files changed, 56 insertions(+), 25 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index c0fd71b..7662a7c 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,8 +1,9 @@ -The ISC License (ISC) -===================== +Copyright 2022 pukkamustard , swrup , zapashcanon -Copyright © 2022, TODO +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index e628def..4c297f0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # leaflet -[leaflet] is an [OCaml] executable/library to TODO. +`leaflet` is an [OCaml] bindings library for the [Leaflet] JavaScript library. ## Installation @@ -24,6 +24,8 @@ For more, have a look at the [example] folder, at the [documentation] or at the ## About +leaflet's original code was taken from a [NGI0 funded project] + - [LICENSE] - [CHANGELOG] @@ -37,4 +39,5 @@ For more, have a look at the [example] folder, at the [documentation] or at the [how to install opam]: https://opam.ocaml.org/doc/Install.html [OCaml]: https://ocaml.org [opam]: https://opam.ocaml.org/ -[leaflet]: TODO/leaflet +[Leaflet]: https://leafletjs.com/ +[NGI0 funded project]: https://nlnet.nl/project/openEngiadina/ diff --git a/dune-project b/dune-project index 5220076..1613163 100644 --- a/dune-project +++ b/dune-project @@ -4,18 +4,18 @@ (name leaflet) -(license ISC) +(license BSD-2-Clause) -(authors "TODO") +(authors "pukkamustard " "swrup " "Léo Andrès ") -(maintainers "TODO") +(maintainers "swrup ") (source - (uri TODO/leaflet)) + (uri git+https://git.zapashcanon.fr/swrup/leaflet.git)) -(homepage TODO/leaflet) +(homepage https://git.zapashcanon.fr/swrup/leaflet) -(bug_reports TODO/leaflet) +(bug_reports https://git.zapashcanon.fr/swrup/leaflet/issues) (documentation TODO/leaflet) @@ -23,11 +23,11 @@ (package (name leaflet) - (synopsis "OCaml library/executable to TODO") + (synopsis "Bindings for the Leaflet JavaScript library") (description - "leaflet is an OCaml library/executable to TODO.") + "leaflet is an OCaml bindings library for the Leaflet JavaScript library.") (tags - (leaflet TODO TODO TODO TODO)) + (leaflet javascript bindings interactive map openstreetmap)) (depends (ocaml (>= 4.08)))) diff --git a/leaflet.opam b/leaflet.opam index 996aee0..deb4d45 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -1,14 +1,19 @@ # This file is generated by dune, edit dune-project instead opam-version: "2.0" -synopsis: "OCaml library/executable to TODO" -description: "leaflet is an OCaml library/executable to TODO." -maintainer: ["TODO"] -authors: ["TODO"] -license: "ISC" -tags: ["leaflet" "TODO" "TODO" "TODO" "TODO"] -homepage: "TODO/leaflet" +synopsis: "Bindings for the Leaflet JavaScript library" +description: + "leaflet is an OCaml bindings library for the Leaflet JavaScript library." +maintainer: ["swrup "] +authors: [ + "pukkamustard " + "swrup " + "Léo Andrès " +] +license: "BSD-2-Clause" +tags: ["leaflet" "javascript" "bindings" "interactive" "map" "openstreetmap"] +homepage: "https://git.zapashcanon.fr/swrup/leaflet" doc: "TODO/leaflet" -bug-reports: "TODO/leaflet" +bug-reports: "https://git.zapashcanon.fr/swrup/leaflet/issues" depends: [ "dune" {>= "2.9"} "ocaml" {>= "4.08"} @@ -30,4 +35,4 @@ build: [ ] ["dune" "install" "-p" name "--create-install-files" name] ] -dev-repo: "TODO/leaflet" +dev-repo: "git+https://git.zapashcanon.fr/swrup/leaflet.git" diff --git a/src/event.ml b/src/event.ml index 6b456d2..2b39417 100644 --- a/src/event.ml +++ b/src/event.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type _ t = | Keyboard : Jv.t -> [> `Keyboard ] t | Mouse : Jv.t -> [> `Mouse ] t diff --git a/src/event.mli b/src/event.mli index 9592bfb..8723a09 100644 --- a/src/event.mli +++ b/src/event.mli @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type _ t = | Keyboard : Jv.t -> [> `Keyboard ] t | Mouse : Jv.t -> [> `Mouse ] t diff --git a/src/global.ml b/src/global.ml index c209f3d..a4ebdfa 100644 --- a/src/global.ml +++ b/src/global.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + let leaflet = match Jv.(find global "L") with | Some l -> l diff --git a/src/latlng.ml b/src/latlng.ml index 6611746..400200b 100644 --- a/src/latlng.ml +++ b/src/latlng.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t = Jv.t let create lat lng = diff --git a/src/latlng.mli b/src/latlng.mli index c63a970..9097890 100644 --- a/src/latlng.mli +++ b/src/latlng.mli @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t val create : float -> float -> t diff --git a/src/layer.ml b/src/layer.ml index fd9b07a..9808ebb 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type _ t = | Basic : Jv.t -> [> `Basic ] t | Geojson : Jv.t -> [> `Geojson ] t diff --git a/src/layer.mli b/src/layer.mli index 0baf3fd..b3816e6 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type _ t = | Basic : Jv.t -> [> `Basic ] t | Geojson : Jv.t -> [> `Geojson ] t diff --git a/src/map.ml b/src/map.ml index 57598f4..259efeb 100644 --- a/src/map.ml +++ b/src/map.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t = Jv.t let of_jv = Fun.id diff --git a/src/map.mli b/src/map.mli index f4f6f2b..96795cb 100644 --- a/src/map.mli +++ b/src/map.mli @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t val create : ?options:Jv.t -> string -> t diff --git a/src/popup.ml b/src/popup.ml index fb0264c..5447cd4 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t = Jv.t let popup = Jv.call Global.leaflet "popup" [||] diff --git a/src/popup.mli b/src/popup.mli index 65e5dfc..ee5df35 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t val set_latlng : Latlng.t -> unit From f32c13eae686023303392f0440ed529ff3b51c5a Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 12 Apr 2022 15:26:49 +0200 Subject: [PATCH 04/43] add point --- src/dune | 2 +- src/event.ml | 8 ++++---- src/event.mli | 4 ++-- src/point.ml | 11 +++++++++++ src/point.mli | 9 +++++++++ 5 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 src/point.ml create mode 100644 src/point.mli diff --git a/src/dune b/src/dune index ed4515f..4e2d45f 100644 --- a/src/dune +++ b/src/dune @@ -1,6 +1,6 @@ (library (public_name leaflet) - (modules event global latlng layer map popup) + (modules event global latlng layer map popup point) (private_modules global) (libraries brr) (js_of_ocaml diff --git a/src/event.ml b/src/event.ml index 2b39417..2b9cb77 100644 --- a/src/event.ml +++ b/src/event.ml @@ -43,11 +43,11 @@ let original_event : [ `Keyboard | `Mouse ] t -> Jv.t = function (** Mouse events *) -let container_point : [ `Mouse ] t -> Jv.t = function - | Mouse e -> Jv.get e "containerPoint" +let container_point : [ `Mouse ] t -> Point.t = function + | Mouse e -> Jv.get e "containerPoint" |> Point.of_jv -let layer_point : [ `Mouse ] t -> Jv.t = function - | Mouse e -> Jv.get e "layerPoint" +let layer_point : [ `Mouse ] t -> Point.t = function + | Mouse e -> Jv.get e "layerPoint" |> Point.of_jv let latlng : [ `Mouse ] t -> Latlng.t = function | Mouse e -> Jv.get e "latlng" |> Latlng.of_jv diff --git a/src/event.mli b/src/event.mli index 8723a09..5793744 100644 --- a/src/event.mli +++ b/src/event.mli @@ -31,9 +31,9 @@ val original_event : [ `Keyboard | `Mouse ] t -> Jv.t (** Mouse events *) -val container_point : [ `Mouse ] t -> Jv.t +val container_point : [ `Mouse ] t -> Point.t -val layer_point : [ `Mouse ] t -> Jv.t +val layer_point : [ `Mouse ] t -> Point.t val latlng : [ `Mouse ] t -> Latlng.t diff --git a/src/point.ml b/src/point.ml new file mode 100644 index 0000000..0191894 --- /dev/null +++ b/src/point.ml @@ -0,0 +1,11 @@ +(* BSD-2-Clause License *) + +type t = + { x : int + ; y : int + } + +let of_jv point = + let x = Jv.get point "x" |> Jv.to_int in + let y = Jv.get point "y" |> Jv.to_int in + { x; y } diff --git a/src/point.mli b/src/point.mli new file mode 100644 index 0000000..2ca4de2 --- /dev/null +++ b/src/point.mli @@ -0,0 +1,9 @@ +(* BSD-2-Clause License *) + +type t = + { x : int + ; y : int + } + +(** [of_jv jv] is [jv] as {!t} *) +val of_jv : Jv.t -> t From 2965572a4b388b16df6b9934d66b9041201166e9 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 19 May 2022 15:46:43 +0200 Subject: [PATCH 05/43] add example --- example/dune | 6 +- example/leaflet.css | 640 ++++++++++++++++++++++++++++++++++++++++++++ example/main.ml | 15 +- example/map.html | 12 + 4 files changed, 671 insertions(+), 2 deletions(-) create mode 100644 example/leaflet.css create mode 100644 example/map.html diff --git a/example/dune b/example/dune index e36b142..80423a9 100644 --- a/example/dune +++ b/example/dune @@ -1,3 +1,7 @@ (executable (name main) - (modules main)) + (modules main) + (libraries leaflet) + (modes js) + (preprocess + (pps js_of_ocaml-ppx))) diff --git a/example/leaflet.css b/example/leaflet.css new file mode 100644 index 0000000..3385b5e --- /dev/null +++ b/example/leaflet.css @@ -0,0 +1,640 @@ +/* required styles */ + +.leaflet-pane, +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-tile-container, +.leaflet-pane > svg, +.leaflet-pane > canvas, +.leaflet-zoom-box, +.leaflet-image-layer, +.leaflet-layer { + position: absolute; + left: 0; + top: 0; + } +.leaflet-container { + overflow: hidden; + } +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + -webkit-user-drag: none; + } +/* Prevents IE11 from highlighting tiles in blue */ +.leaflet-tile::selection { + background: transparent; +} +/* Safari renders non-retina tile on retina better with this, but Chrome is worse */ +.leaflet-safari .leaflet-tile { + image-rendering: -webkit-optimize-contrast; + } +/* hack that prevents hw layers "stretching" when loading new tiles */ +.leaflet-safari .leaflet-tile-container { + width: 1600px; + height: 1600px; + -webkit-transform-origin: 0 0; + } +.leaflet-marker-icon, +.leaflet-marker-shadow { + display: block; + } +/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */ +/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */ +.leaflet-container .leaflet-overlay-pane svg, +.leaflet-container .leaflet-marker-pane img, +.leaflet-container .leaflet-shadow-pane img, +.leaflet-container .leaflet-tile-pane img, +.leaflet-container img.leaflet-image-layer, +.leaflet-container .leaflet-tile { + max-width: none !important; + max-height: none !important; + } + +.leaflet-container.leaflet-touch-zoom { + -ms-touch-action: pan-x pan-y; + touch-action: pan-x pan-y; + } +.leaflet-container.leaflet-touch-drag { + -ms-touch-action: pinch-zoom; + /* Fallback for FF which doesn't support pinch-zoom */ + touch-action: none; + touch-action: pinch-zoom; +} +.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom { + -ms-touch-action: none; + touch-action: none; +} +.leaflet-container { + -webkit-tap-highlight-color: transparent; +} +.leaflet-container a { + -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4); +} +.leaflet-tile { + filter: inherit; + visibility: hidden; + } +.leaflet-tile-loaded { + visibility: inherit; + } +.leaflet-zoom-box { + width: 0; + height: 0; + -moz-box-sizing: border-box; + box-sizing: border-box; + z-index: 800; + } +/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */ +.leaflet-overlay-pane svg { + -moz-user-select: none; + } + +.leaflet-pane { z-index: 400; } + +.leaflet-tile-pane { z-index: 200; } +.leaflet-overlay-pane { z-index: 400; } +.leaflet-shadow-pane { z-index: 500; } +.leaflet-marker-pane { z-index: 600; } +.leaflet-tooltip-pane { z-index: 650; } +.leaflet-popup-pane { z-index: 700; } + +.leaflet-map-pane canvas { z-index: 100; } +.leaflet-map-pane svg { z-index: 200; } + +.leaflet-vml-shape { + width: 1px; + height: 1px; + } +.lvml { + behavior: url(#default#VML); + display: inline-block; + position: absolute; + } + + +/* control positioning */ + +.leaflet-control { + position: relative; + z-index: 800; + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; + } +.leaflet-top, +.leaflet-bottom { + position: absolute; + z-index: 1000; + pointer-events: none; + } +.leaflet-top { + top: 0; + } +.leaflet-right { + right: 0; + } +.leaflet-bottom { + bottom: 0; + } +.leaflet-left { + left: 0; + } +.leaflet-control { + float: left; + clear: both; + } +.leaflet-right .leaflet-control { + float: right; + } +.leaflet-top .leaflet-control { + margin-top: 10px; + } +.leaflet-bottom .leaflet-control { + margin-bottom: 10px; + } +.leaflet-left .leaflet-control { + margin-left: 10px; + } +.leaflet-right .leaflet-control { + margin-right: 10px; + } + + +/* zoom and fade animations */ + +.leaflet-fade-anim .leaflet-tile { + will-change: opacity; + } +.leaflet-fade-anim .leaflet-popup { + opacity: 0; + -webkit-transition: opacity 0.2s linear; + -moz-transition: opacity 0.2s linear; + transition: opacity 0.2s linear; + } +.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { + opacity: 1; + } +.leaflet-zoom-animated { + -webkit-transform-origin: 0 0; + -ms-transform-origin: 0 0; + transform-origin: 0 0; + } +.leaflet-zoom-anim .leaflet-zoom-animated { + will-change: transform; + } +.leaflet-zoom-anim .leaflet-zoom-animated { + -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); + -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); + transition: transform 0.25s cubic-bezier(0,0,0.25,1); + } +.leaflet-zoom-anim .leaflet-tile, +.leaflet-pan-anim .leaflet-tile { + -webkit-transition: none; + -moz-transition: none; + transition: none; + } + +.leaflet-zoom-anim .leaflet-zoom-hide { + visibility: hidden; + } + + +/* cursors */ + +.leaflet-interactive { + cursor: pointer; + } +.leaflet-grab { + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: grab; + } +.leaflet-crosshair, +.leaflet-crosshair .leaflet-interactive { + cursor: crosshair; + } +.leaflet-popup-pane, +.leaflet-control { + cursor: auto; + } +.leaflet-dragging .leaflet-grab, +.leaflet-dragging .leaflet-grab .leaflet-interactive, +.leaflet-dragging .leaflet-marker-draggable { + cursor: move; + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + cursor: grabbing; + } + +/* marker & overlays interactivity */ +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-image-layer, +.leaflet-pane > svg path, +.leaflet-tile-container { + pointer-events: none; + } + +.leaflet-marker-icon.leaflet-interactive, +.leaflet-image-layer.leaflet-interactive, +.leaflet-pane > svg path.leaflet-interactive, +svg.leaflet-image-layer.leaflet-interactive path { + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; + } + +/* visual tweaks */ + +.leaflet-container { + background: #ddd; + outline: 0; + } +.leaflet-container a { + color: #0078A8; + } +.leaflet-container a.leaflet-active { + outline: 2px solid orange; + } +.leaflet-zoom-box { + border: 2px dotted #38f; + background: rgba(255,255,255,0.5); + } + + +/* general typography */ +.leaflet-container { + font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; + } + + +/* general toolbar styles */ + +.leaflet-bar { + box-shadow: 0 1px 5px rgba(0,0,0,0.65); + border-radius: 4px; + } +.leaflet-bar a, +.leaflet-bar a:hover { + background-color: #fff; + border-bottom: 1px solid #ccc; + width: 26px; + height: 26px; + line-height: 26px; + display: block; + text-align: center; + text-decoration: none; + color: black; + } +.leaflet-bar a, +.leaflet-control-layers-toggle { + background-position: 50% 50%; + background-repeat: no-repeat; + display: block; + } +.leaflet-bar a:hover { + background-color: #f4f4f4; + } +.leaflet-bar a:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; + } +.leaflet-bar a:last-child { + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom: none; + } +.leaflet-bar a.leaflet-disabled { + cursor: default; + background-color: #f4f4f4; + color: #bbb; + } + +.leaflet-touch .leaflet-bar a { + width: 30px; + height: 30px; + line-height: 30px; + } +.leaflet-touch .leaflet-bar a:first-child { + border-top-left-radius: 2px; + border-top-right-radius: 2px; + } +.leaflet-touch .leaflet-bar a:last-child { + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; + } + +/* zoom control */ + +.leaflet-control-zoom-in, +.leaflet-control-zoom-out { + font: bold 18px 'Lucida Console', Monaco, monospace; + text-indent: 1px; + } + +.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out { + font-size: 22px; + } + + +/* layers control */ + +.leaflet-control-layers { + box-shadow: 0 1px 5px rgba(0,0,0,0.4); + background: #fff; + border-radius: 5px; + } +.leaflet-control-layers-toggle { + background-image: url(/assets/img/layers.png); + width: 36px; + height: 36px; + } +.leaflet-retina .leaflet-control-layers-toggle { + background-image: url(/assets/img/layers-2x.png); + background-size: 26px 26px; + } +.leaflet-touch .leaflet-control-layers-toggle { + width: 44px; + height: 44px; + } +.leaflet-control-layers .leaflet-control-layers-list, +.leaflet-control-layers-expanded .leaflet-control-layers-toggle { + display: none; + } +.leaflet-control-layers-expanded .leaflet-control-layers-list { + display: block; + position: relative; + } +.leaflet-control-layers-expanded { + padding: 6px 10px 6px 6px; + color: #333; + background: #fff; + } +.leaflet-control-layers-scrollbar { + overflow-y: scroll; + overflow-x: hidden; + padding-right: 5px; + } +.leaflet-control-layers-selector { + margin-top: 2px; + position: relative; + top: 1px; + } +.leaflet-control-layers label { + display: block; + } +.leaflet-control-layers-separator { + height: 0; + border-top: 1px solid #ddd; + margin: 5px -10px 5px -6px; + } + +/* Default icon URLs */ +.leaflet-default-icon-path { + background-image: url(/assets/img/marker-icon.png); + } + + +/* attribution and scale controls */ + +.leaflet-container .leaflet-control-attribution { + background: #fff; + background: rgba(255, 255, 255, 0.7); + margin: 0; + } +.leaflet-control-attribution, +.leaflet-control-scale-line { + padding: 0 5px; + color: #333; + } +.leaflet-control-attribution a { + text-decoration: none; + } +.leaflet-control-attribution a:hover { + text-decoration: underline; + } +.leaflet-container .leaflet-control-attribution, +.leaflet-container .leaflet-control-scale { + font-size: 11px; + } +.leaflet-left .leaflet-control-scale { + margin-left: 5px; + } +.leaflet-bottom .leaflet-control-scale { + margin-bottom: 5px; + } +.leaflet-control-scale-line { + border: 2px solid #777; + border-top: none; + line-height: 1.1; + padding: 2px 5px 1px; + font-size: 11px; + white-space: nowrap; + overflow: hidden; + -moz-box-sizing: border-box; + box-sizing: border-box; + + background: #fff; + background: rgba(255, 255, 255, 0.5); + } +.leaflet-control-scale-line:not(:first-child) { + border-top: 2px solid #777; + border-bottom: none; + margin-top: -2px; + } +.leaflet-control-scale-line:not(:first-child):not(:last-child) { + border-bottom: 2px solid #777; + } + +.leaflet-touch .leaflet-control-attribution, +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + box-shadow: none; + } +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + border: 2px solid rgba(0,0,0,0.2); + background-clip: padding-box; + } + + +/* popup */ + +.leaflet-popup { + position: absolute; + text-align: center; + margin-bottom: 20px; + } +.leaflet-popup-content-wrapper { + padding: 1px; + text-align: left; + border-radius: 12px; + } +.leaflet-popup-content { + margin: 13px 19px; + line-height: 1.4; + } +.leaflet-popup-content p { + margin: 18px 0; + } +.leaflet-popup-tip-container { + width: 40px; + height: 20px; + position: absolute; + left: 50%; + margin-left: -20px; + overflow: hidden; + pointer-events: none; + } +.leaflet-popup-tip { + width: 17px; + height: 17px; + padding: 1px; + + margin: -10px auto 0; + + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); + } +.leaflet-popup-content-wrapper, +.leaflet-popup-tip { + background: white; + color: #333; + box-shadow: 0 3px 14px rgba(0,0,0,0.4); + } +.leaflet-container a.leaflet-popup-close-button { + position: absolute; + top: 0; + right: 0; + padding: 4px 4px 0 0; + border: none; + text-align: center; + width: 18px; + height: 14px; + font: 16px/14px Tahoma, Verdana, sans-serif; + color: #c3c3c3; + text-decoration: none; + font-weight: bold; + background: transparent; + } +.leaflet-container a.leaflet-popup-close-button:hover { + color: #999; + } +.leaflet-popup-scrolled { + overflow: auto; + border-bottom: 1px solid #ddd; + border-top: 1px solid #ddd; + } + +.leaflet-oldie .leaflet-popup-content-wrapper { + -ms-zoom: 1; + } +.leaflet-oldie .leaflet-popup-tip { + width: 24px; + margin: 0 auto; + + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; + filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); + } +.leaflet-oldie .leaflet-popup-tip-container { + margin-top: -1px; + } + +.leaflet-oldie .leaflet-control-zoom, +.leaflet-oldie .leaflet-control-layers, +.leaflet-oldie .leaflet-popup-content-wrapper, +.leaflet-oldie .leaflet-popup-tip { + border: 1px solid #999; + } + + +/* div icon */ + +.leaflet-div-icon { + background: #fff; + border: 1px solid #666; + } + + +/* Tooltip */ +/* Base styles for the element that has a tooltip */ +.leaflet-tooltip { + position: absolute; + padding: 6px; + background-color: #fff; + border: 1px solid #fff; + border-radius: 3px; + color: #222; + white-space: nowrap; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + pointer-events: none; + box-shadow: 0 1px 3px rgba(0,0,0,0.4); + } +.leaflet-tooltip.leaflet-clickable { + cursor: pointer; + pointer-events: auto; + } +.leaflet-tooltip-top:before, +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + position: absolute; + pointer-events: none; + border: 6px solid transparent; + background: transparent; + content: ""; + } + +/* Directions */ + +.leaflet-tooltip-bottom { + margin-top: 6px; +} +.leaflet-tooltip-top { + margin-top: -6px; +} +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-top:before { + left: 50%; + margin-left: -6px; + } +.leaflet-tooltip-top:before { + bottom: 0; + margin-bottom: -12px; + border-top-color: #fff; + } +.leaflet-tooltip-bottom:before { + top: 0; + margin-top: -12px; + margin-left: -6px; + border-bottom-color: #fff; + } +.leaflet-tooltip-left { + margin-left: -6px; +} +.leaflet-tooltip-right { + margin-left: 6px; +} +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + top: 50%; + margin-top: -6px; + } +.leaflet-tooltip-left:before { + right: 0; + margin-right: -12px; + border-left-color: #fff; + } +.leaflet-tooltip-right:before { + left: 0; + margin-left: -12px; + border-right-color: #fff; + } diff --git a/example/main.ml b/example/main.ml index 16c9b9f..9b8e97d 100644 --- a/example/main.ml +++ b/example/main.ml @@ -1 +1,14 @@ -let () = Format.printf "TODO@." +(* create map *) +let map = + let container_id = "map" in + Leaflet.Map.create container_id + +(* setup map *) +let () = + (* set osm layer *) + let osm_layer = Leaflet.Layer.create_tile_osm None in + Leaflet.Layer.add_to map osm_layer; + + (* set view *) + let latlng = Leaflet.Latlng.create 40.71 (-74.0) in + ignore @@ Leaflet.Map.set_view latlng ~zoom:(Some 13) map diff --git a/example/map.html b/example/map.html new file mode 100644 index 0000000..341173f --- /dev/null +++ b/example/map.html @@ -0,0 +1,12 @@ + + + + + + + +
+
+
+ + From d242b1ac6e998a951b98a3368c70957584b014a3 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 19 May 2022 16:16:37 +0200 Subject: [PATCH 06/43] make Map.create take Brr.El --- example/dune | 2 +- example/main.ml | 8 ++++++-- src/map.ml | 6 ++++-- src/map.mli | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/example/dune b/example/dune index 80423a9..1b81cc6 100644 --- a/example/dune +++ b/example/dune @@ -1,7 +1,7 @@ (executable (name main) (modules main) - (libraries leaflet) + (libraries brr leaflet) (modes js) (preprocess (pps js_of_ocaml-ppx))) diff --git a/example/main.ml b/example/main.ml index 9b8e97d..9e685c4 100644 --- a/example/main.ml +++ b/example/main.ml @@ -1,7 +1,11 @@ (* create map *) let map = - let container_id = "map" in - Leaflet.Map.create container_id + let container = + match Brr.Document.find_el_by_id Brr.G.document (Jstr.of_string "map") with + | None -> failwith "map container not found" + | Some el -> el + in + Leaflet.Map.create container (* setup map *) let () = diff --git a/src/map.ml b/src/map.ml index 259efeb..8277a9a 100644 --- a/src/map.ml +++ b/src/map.ml @@ -6,8 +6,10 @@ let of_jv = Fun.id let to_jv = Fun.id -let create ?(options = Jv.null) container_id = - Jv.call Global.leaflet "map" [| Jv.of_string container_id; options |] +let create ?(options = Jv.null) container = + match Brr.El.at (Jstr.of_string "id") container with + | None -> failwith "container doesn't have id" + | Some id -> Jv.call Global.leaflet "map" [| Jv.of_jstr id; options |] let invalidate_size map = let (_ : Jv.t) = Jv.call map "invalidateSize" [| Jv.true' |] in diff --git a/src/map.mli b/src/map.mli index 96795cb..15c1f2b 100644 --- a/src/map.mli +++ b/src/map.mli @@ -2,7 +2,7 @@ type t -val create : ?options:Jv.t -> string -> t +val create : ?options:Jv.t -> Brr.El.t -> t val invalidate_size : t -> unit From 21bf82239b4b3b6d8e701d2ce5ec235d9c9ae359 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 19 May 2022 22:42:28 +0200 Subject: [PATCH 07/43] add documentation, remove Map.as_target --- doc/index.mld | 14 ++------------ src/latlng.mli | 8 ++++++++ src/layer.ml | 1 - src/layer.mli | 14 ++++++++++++++ src/map.ml | 4 +--- src/map.mli | 23 ++++++++++++++++++++--- src/popup.mli | 5 +++++ 7 files changed, 50 insertions(+), 19 deletions(-) diff --git a/doc/index.mld b/doc/index.mld index c248edf..1676769 100644 --- a/doc/index.mld +++ b/doc/index.mld @@ -1,17 +1,7 @@ -{0 leaflet} +{0 Leaflet} -{{:https://TODO/leaflet} leaflet} is an {{:https://ocaml.org} OCaml} library/executable to TODO. - -{1:api API} +Leaflet is an [OCaml] bindings library for the {{:https://leafletjs.com} Leaflet} JavaScript library. {!modules: Leaflet } - -{1:private_api Private API} - -You shouldn't have to use any of these modules, they're used internally only. - -{!modules: -TODO -} diff --git a/src/latlng.mli b/src/latlng.mli index 9097890..120d165 100644 --- a/src/latlng.mli +++ b/src/latlng.mli @@ -2,14 +2,22 @@ type t +(** [create lat lng] is an object representing a geographical point with the + given latitude and longitude *) val create : float -> float -> t +(** [lat o] is the latitude of [o] *) val lat : t -> float +(** [lng o] is the longitude of [o] *) val lng : t -> float +(** [equals a b] is true iff [a] and [b] is at the same position (within a small + margin of error) *) val equals : t -> t -> bool +(** [of_jv jv] is [jv] as a [Latlng.t] *) val of_jv : Jv.t -> t +(** [to_jv o] is [o] as a {!Jv.t} *) val to_jv : t -> Jv.t diff --git a/src/layer.ml b/src/layer.ml index 9808ebb..b1e8977 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -71,7 +71,6 @@ let create_marker : Latlng.t -> [ `Marker ] t = let create_tile_osm : string option -> [ `Tile ] t = fun url -> - (* see https://wiki.openstreetmap.org/wiki/Tile_servers *) let url = Option.value url ~default:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" diff --git a/src/layer.mli b/src/layer.mli index b3816e6..d049182 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -8,32 +8,46 @@ type _ t = (** Basic layers *) +(** [add_to map layer] adds [layer] to [map] *) val add_to : Map.t -> _ t -> unit +(** [remove layer] removes [layer] from the map it is currently active on *) val remove : _ t -> unit +(** [remove_from map layer] removes [layer] from [map] *) val remove_from : Map.t -> _ t -> unit +(** [bind_popup popup layer] binds [popup] to [layer] *) val bind_popup : Brr.El.t -> _ t -> unit +(** [unbind_popup layer] unbinds the popup bound to [layer] *) val unbind_popup : _ t -> unit +(** [open_popup layer] opens the popup bound to [layer] *) val open_popup : _ t -> unit +(** [close_popup layer] closes the popup bound to [layer] *) val close_popup : _ t -> unit +(** [get_popup layer] is the popup bound to [layer] *) val get_popup : _ t -> Popup.t +(** [to_jv o] is [o] as a {!Jv.t} *) val to_jv : _ t -> Jv.t (** Geojson layers *) +(** [create_geojson geojson] is a new geojson layer *) val create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t (** Marker layers *) +(** [create_marker latlng] is a new marker with the same position as latlng *) val create_marker : Latlng.t -> [ `Marker ] t (** Tile layers *) +(** [create_tile_osm Some(url)] is a new tile layer with tile server specified + by [url]. Tile server default to [openstreetmap.org]. See + {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) val create_tile_osm : string option -> [ `Tile ] t diff --git a/src/map.ml b/src/map.ml index 8277a9a..bbd5da3 100644 --- a/src/map.ml +++ b/src/map.ml @@ -30,8 +30,6 @@ let set_view latlng ~zoom map = in () -let as_target map = Brr.Ev.target_of_jv map - let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> t -> unit = fun event handler map -> let name = Event.sub_to_string event in @@ -43,5 +41,5 @@ let get_center map = Latlng.of_jv @@ Jv.call map "getCenter" [||] let get_zoom map = Jv.call map "getZoom" [||] |> Jv.to_int -let wrapped_latlng latlng map = +let wrap_latlng latlng map = Latlng.of_jv @@ Jv.call map "wrapLatLng" [| Latlng.to_jv latlng |] diff --git a/src/map.mli b/src/map.mli index 15c1f2b..d027da4 100644 --- a/src/map.mli +++ b/src/map.mli @@ -2,26 +2,43 @@ type t +(** [create container] creates a map on [container]. * To have a functional map + you will need to add a tile layer to it. *) val create : ?options:Jv.t -> Brr.El.t -> t +(** [invalidate_size map] checks if the map container size changed and updates + the map if so *) val invalidate_size : t -> unit +(** [set_view latlng Some(zoom) map] sets the view of the [map] (geographical + center and zoom) *) val set_view : Latlng.t -> zoom:int option -> t -> unit +(** [fit_world map] sets a map view that mostly contains the whole world with + the maximum zoom level possible *) val fit_world : t -> unit +(** [get_container map] is the HTML element that contains [map] *) val get_container : t -> Brr.El.t +(** [on event handler map] add an event listener on [map] for event [event] with + handler [handler] *) val on : 'a Event.sub -> ('a Event.t -> 'b) -> t -> unit +(** [get_center map] is the geographical center of the map view *) val get_center : t -> Latlng.t +(** [get_zoom map] is the current zoom level of the map view *) val get_zoom : t -> int -val wrapped_latlng : Latlng.t -> t -> Latlng.t - -val as_target : t -> Brr.Ev.target +(** [wrap_latlng latlng map] returns a new [Latlng.t] where lat and lng has been + wrapped according to the map's CRS's wrapLat and wrapLng properties, if they + are outside the CRS's bounds. By default this means longitude is wrapped + around the dateline so its value is between -180 and +180 degrees *) +val wrap_latlng : Latlng.t -> t -> Latlng.t +(** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t +(** [to_jv o] is [o] as {!Jv.t} *) val to_jv : t -> Jv.t diff --git a/src/popup.mli b/src/popup.mli index ee5df35..9983c5c 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -2,12 +2,17 @@ type t +(** [set_latlng latlng] changes the popup position to the given point*) val set_latlng : Latlng.t -> unit +(** [set_content s] changes the popup content to [s]*) val set_content : string -> unit +(** [open_on map] * Adds the popup to [map] and closes the previous one. *) val open_on : Map.t -> unit +(** [close map] * closes the popup of [map]*) val close : Map.t -> unit +(** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t From 0a5f5519daeb60f593931f2f5ad142c432f2de5e Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 19 May 2022 23:02:04 +0200 Subject: [PATCH 08/43] add usage to readme --- .ocamlformat | 2 +- CHANGES.md | 4 +++- README.md | 11 +++++------ dune-project | 1 + leaflet.opam | 1 + 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.ocamlformat b/.ocamlformat index 1b64a37..cec2d50 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version=0.21.0 +version=0.22.4 assignment-operator=end-line break-cases=fit break-fun-decl=wrap diff --git a/CHANGES.md b/CHANGES.md index d9cd2e7..4cff088 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1 +1,3 @@ -## unreleased +## 0.1 + +Initial release. diff --git a/README.md b/README.md index 4c297f0..ffa9b2e 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,12 @@ If you don't have `opam`, you can install it following the [how to install opam] If you can't or don't want to use `opam`, consult the [opam file] for build instructions. -## Quickstart +## Usage -```ocaml -let () = Format.printf "TODO@." -``` +Have a look at the [example] folder. +The documentation can be consulted via `odig doc leaflet`. -For more, have a look at the [example] folder, at the [documentation] or at the [test suite]. +You will also need [leaflet's files] (CSS and images). ## About @@ -35,9 +34,9 @@ leaflet's original code was taken from a [NGI0 funded project] [opam file]: ./leaflet.opam [test suite]: ./test -[documentation]: TODO/leaflet [how to install opam]: https://opam.ocaml.org/doc/Install.html [OCaml]: https://ocaml.org [opam]: https://opam.ocaml.org/ [Leaflet]: https://leafletjs.com/ +[leaflet's files]: https://leafletjs.com/download.html [NGI0 funded project]: https://nlnet.nl/project/openEngiadina/ diff --git a/dune-project b/dune-project index 1613163..1b5b654 100644 --- a/dune-project +++ b/dune-project @@ -29,5 +29,6 @@ (tags (leaflet javascript bindings interactive map openstreetmap)) (depends + brr (ocaml (>= 4.08)))) diff --git a/leaflet.opam b/leaflet.opam index deb4d45..70dc18a 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -16,6 +16,7 @@ doc: "TODO/leaflet" bug-reports: "https://git.zapashcanon.fr/swrup/leaflet/issues" depends: [ "dune" {>= "2.9"} + "brr" "ocaml" {>= "4.08"} "odoc" {with-doc} ] From bf66ab75fbc0aa64eb6614298a2011766221a12e Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 18 Jun 2022 07:53:26 +0200 Subject: [PATCH 09/43] change map creation --- example/main.ml | 8 +------- src/map.ml | 11 +++++++---- src/map.mli | 11 ++++++++--- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/example/main.ml b/example/main.ml index 9e685c4..43b9fcd 100644 --- a/example/main.ml +++ b/example/main.ml @@ -1,11 +1,5 @@ (* create map *) -let map = - let container = - match Brr.Document.find_el_by_id Brr.G.document (Jstr.of_string "map") with - | None -> failwith "map container not found" - | Some el -> el - in - Leaflet.Map.create container +let map = Leaflet.Map.create_on "map" (* setup map *) let () = diff --git a/src/map.ml b/src/map.ml index bbd5da3..2f2db23 100644 --- a/src/map.ml +++ b/src/map.ml @@ -6,10 +6,13 @@ let of_jv = Fun.id let to_jv = Fun.id -let create ?(options = Jv.null) container = - match Brr.El.at (Jstr.of_string "id") container with - | None -> failwith "container doesn't have id" - | Some id -> Jv.call Global.leaflet "map" [| Jv.of_jstr id; options |] +let create_on ?(options = Jv.null) id = + Jv.call Global.leaflet "map" [| Jv.of_string id; options |] + +let create_from_div ?(options = Jv.null) container = + if Brr.El.has_tag_name Brr.El.Name.div container then + Jv.call Global.leaflet "map" [| Brr.El.to_jv container; options |] + else failwith "container is not a
" let invalidate_size map = let (_ : Jv.t) = Jv.call map "invalidateSize" [| Jv.true' |] in diff --git a/src/map.mli b/src/map.mli index d027da4..c1a7770 100644 --- a/src/map.mli +++ b/src/map.mli @@ -2,9 +2,14 @@ type t -(** [create container] creates a map on [container]. * To have a functional map - you will need to add a tile layer to it. *) -val create : ?options:Jv.t -> Brr.El.t -> t +(** [create id] creates a map on the
with DOM id [id]. To have a + functional map you will need to add a tile layer to it. *) +val create_on : ?options:Jv.t -> string -> t + +(** [create_from_div container] creates a map given [container], an instance of + a
HTML element. To have a functional map you will need to add a tile + layer to it. *) +val create_from_div : ?options:Jv.t -> Brr.El.t -> t (** [invalidate_size map] checks if the map container size changed and updates the map if so *) From d1ddafd945dc0abc16a167d82a8bf0f61d3552ee Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 18 Jun 2022 20:47:19 +0200 Subject: [PATCH 10/43] add js_of_ocaml to package dependency --- dune-project | 1 + example/dune | 4 +--- leaflet.opam | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dune-project b/dune-project index 1b5b654..896dd1a 100644 --- a/dune-project +++ b/dune-project @@ -30,5 +30,6 @@ (leaflet javascript bindings interactive map openstreetmap)) (depends brr + js_of_ocaml (ocaml (>= 4.08)))) diff --git a/example/dune b/example/dune index 1b81cc6..b868e46 100644 --- a/example/dune +++ b/example/dune @@ -2,6 +2,4 @@ (name main) (modules main) (libraries brr leaflet) - (modes js) - (preprocess - (pps js_of_ocaml-ppx))) + (modes js)) diff --git a/leaflet.opam b/leaflet.opam index 70dc18a..1b6ae70 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -17,6 +17,7 @@ bug-reports: "https://git.zapashcanon.fr/swrup/leaflet/issues" depends: [ "dune" {>= "2.9"} "brr" + "js_of_ocaml" "ocaml" {>= "4.08"} "odoc" {with-doc} ] From e33ad46092dbadeb0f6cccdaf4750feb049cf901 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 06:52:05 +0200 Subject: [PATCH 11/43] add of_jv, on, ?options for bind_popup --- src/layer.ml | 29 ++++++++++++++++++++++++++--- src/layer.mli | 15 ++++++++++++++- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index b1e8977..beef402 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -6,6 +6,12 @@ type _ t = | Marker : Jv.t -> [> `Marker ] t | Tile : Jv.t -> [> `Tile ] t +type _ sub = + | Basic : [> `Basic ] sub + | Geojson : [> `Geojson ] sub + | Marker : [> `Marker ] sub + | Tile : [> `Tile ] sub + (** Basic layers *) let add_to : type kind. Map.t -> kind t -> unit = @@ -25,10 +31,10 @@ let remove_from : type kind. Map.t -> kind t -> unit = let (_ : Jv.t) = Jv.call l "removeFrom" [| Map.to_jv map |] in () -let bind_popup : type kind. Brr.El.t -> kind t -> unit = - fun el -> function +let bind_popup : type kind. Brr.El.t -> ?options:Jv.t -> kind t -> unit = + fun el ?(options = Jv.null) -> function | Basic l | Geojson l | Marker l | Tile l -> - let (_ : Jv.t) = Jv.call l "bindPopup" [| Brr.El.to_jv el |] in + let (_ : Jv.t) = Jv.call l "bindPopup" [| Brr.El.to_jv el; options |] in () let unbind_popup : type kind. kind t -> unit = function @@ -53,6 +59,23 @@ let get_popup : type kind. kind t -> Popup.t = function let to_jv : type kind. kind t -> Jv.t = function | Basic l | Geojson l | Marker l | Tile l -> l +let of_jv : type kind. kind sub -> Jv.t -> kind t = + fun tag l -> + match tag with + | Basic -> Basic l + | Geojson -> Geojson l + | Marker -> Marker l + | Tile -> Tile l + +let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> 'c t -> unit = + fun event handler layer -> + let name = Event.sub_to_string event in + let handler v = handler @@ Event.of_jv event v in + let (_ : Jv.t) = + Jv.call (to_jv layer) "on" [| Jv.of_string name; Jv.repr handler |] + in + () + (** Geojson layers *) let create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t = diff --git a/src/layer.mli b/src/layer.mli index d049182..309d1f5 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -6,6 +6,12 @@ type _ t = | Marker : Jv.t -> [> `Marker ] t | Tile : Jv.t -> [> `Tile ] t +type _ sub = + | Basic : [> `Basic ] sub + | Geojson : [> `Geojson ] sub + | Marker : [> `Marker ] sub + | Tile : [> `Tile ] sub + (** Basic layers *) (** [add_to map layer] adds [layer] to [map] *) @@ -18,7 +24,7 @@ val remove : _ t -> unit val remove_from : Map.t -> _ t -> unit (** [bind_popup popup layer] binds [popup] to [layer] *) -val bind_popup : Brr.El.t -> _ t -> unit +val bind_popup : Brr.El.t -> ?options:Jv.t -> _ t -> unit (** [unbind_popup layer] unbinds the popup bound to [layer] *) val unbind_popup : _ t -> unit @@ -35,6 +41,13 @@ val get_popup : _ t -> Popup.t (** [to_jv o] is [o] as a {!Jv.t} *) val to_jv : _ t -> Jv.t +(** [of_jv tag o] is [o] as a [tag t] *) +val of_jv : 'a sub -> Jv.t -> 'a t + +(** [on event handler layer] add an event listener on [layer] for event [event] + with handler [handler] *) +val on : 'a Event.sub -> ('a Event.t -> 'b) -> 'c t -> unit + (** Geojson layers *) (** [create_geojson geojson] is a new geojson layer *) From 69024b75da53c4c644b16a2bc9657f2040a6f609 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 07:57:38 +0200 Subject: [PATCH 12/43] add icon --- src/dune | 2 +- src/icon.ml | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/icon.mli | 21 +++++++++++++++++++++ src/point.ml | 3 +++ src/point.mli | 3 +++ 5 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/icon.ml create mode 100644 src/icon.mli diff --git a/src/dune b/src/dune index 4e2d45f..52d85ee 100644 --- a/src/dune +++ b/src/dune @@ -1,6 +1,6 @@ (library (public_name leaflet) - (modules event global latlng layer map popup point) + (modules event global latlng layer map popup point icon) (private_modules global) (libraries brr) (js_of_ocaml diff --git a/src/icon.ml b/src/icon.ml new file mode 100644 index 0000000..0073d68 --- /dev/null +++ b/src/icon.ml @@ -0,0 +1,47 @@ +(* BSD-2-Clause License *) + +type t = Jv.t + +type opt = + | Icon_retina_url of string + | Icon_size of Point.t + | Icon_anchor of Point.t + | Popup_anchor of Point.t + | Tooltip_anchor of Point.t + | Shadow_url of string + | Shadow_retina_url of string + | Shadow_size of Point.t + | Shadow_anchor of Point.t + | Class_name of string + | Cross_origin of string option + +let to_string = function + | Icon_retina_url _ -> "iconRetinaUrl" + | Icon_size _ -> "iconSize" + | Icon_anchor _ -> "iconAnchor" + | Popup_anchor _ -> "popupAnchor" + | Tooltip_anchor _ -> "tooltipAnchor" + | Shadow_url _ -> "shadowUrl" + | Shadow_retina_url _ -> "shadowRetinaUrl" + | Shadow_size _ -> "shadowSize" + | Shadow_anchor _ -> "shadowAnchor" + | Class_name _ -> "className" + | Cross_origin _ -> "crossOrigin" + +let to_jv = function + | Icon_size p + | Icon_anchor p + | Popup_anchor p + | Tooltip_anchor p + | Shadow_size p + | Shadow_anchor p -> + Point.to_jv p + | Icon_retina_url s | Shadow_url s | Shadow_retina_url s | Class_name s -> + Jv.of_string s + | Cross_origin o -> ( + match o with Some s -> Jv.of_string s | None -> Jv.of_bool false ) + +let create icon_url options = + let l = List.map (fun o -> (to_string o, to_jv o)) options in + let tab = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in + Jv.call Global.leaflet "icon" [| Jv.obj tab |] diff --git a/src/icon.mli b/src/icon.mli new file mode 100644 index 0000000..0d58709 --- /dev/null +++ b/src/icon.mli @@ -0,0 +1,21 @@ +(* BSD-2-Clause License *) + +type t + +(* type for icon option used to create an icon*) +type opt = + | Icon_retina_url of string + | Icon_size of Point.t + | Icon_anchor of Point.t + | Popup_anchor of Point.t + | Tooltip_anchor of Point.t + | Shadow_url of string + | Shadow_retina_url of string + | Shadow_size of Point.t + | Shadow_anchor of Point.t + | Class_name of string + | Cross_origin of string option + +(** [create icon_url options] Creates an icon instance with the given [options], + and the required `iconUrl` option set to [icon_url] *) +val create : string -> opt list -> t diff --git a/src/point.ml b/src/point.ml index 0191894..00fceb9 100644 --- a/src/point.ml +++ b/src/point.ml @@ -9,3 +9,6 @@ let of_jv point = let x = Jv.get point "x" |> Jv.to_int in let y = Jv.get point "y" |> Jv.to_int in { x; y } + +let to_jv point = + Jv.call Global.leaflet "point" [| Jv.of_int point.x; Jv.of_int point.y |] diff --git a/src/point.mli b/src/point.mli index 2ca4de2..a9b9430 100644 --- a/src/point.mli +++ b/src/point.mli @@ -7,3 +7,6 @@ type t = (** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t + +(** [to_jv o] is [o] as {!Jv.t} *) +val to_jv : t -> Jv.t From 6aca93ebe96187127f559699c36234005d4122d0 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 08:16:21 +0200 Subject: [PATCH 13/43] add marker options --- src/icon.ml | 6 ++++-- src/icon.mli | 3 +++ src/layer.ml | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- src/layer.mli | 16 +++++++++++++++- 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/icon.ml b/src/icon.ml index 0073d68..369c288 100644 --- a/src/icon.ml +++ b/src/icon.ml @@ -2,6 +2,8 @@ type t = Jv.t +let to_jv = Fun.id + type opt = | Icon_retina_url of string | Icon_size of Point.t @@ -28,7 +30,7 @@ let to_string = function | Class_name _ -> "className" | Cross_origin _ -> "crossOrigin" -let to_jv = function +let opt_to_jv = function | Icon_size p | Icon_anchor p | Popup_anchor p @@ -42,6 +44,6 @@ let to_jv = function match o with Some s -> Jv.of_string s | None -> Jv.of_bool false ) let create icon_url options = - let l = List.map (fun o -> (to_string o, to_jv o)) options in + let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in let tab = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in Jv.call Global.leaflet "icon" [| Jv.obj tab |] diff --git a/src/icon.mli b/src/icon.mli index 0d58709..df3b33e 100644 --- a/src/icon.mli +++ b/src/icon.mli @@ -2,6 +2,9 @@ type t +(** [to_jv o] is [o] as {!Jv.t} *) +val to_jv : t -> Jv.t + (* type for icon option used to create an icon*) type opt = | Icon_retina_url of string diff --git a/src/layer.ml b/src/layer.ml index beef402..7f34d54 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -85,9 +85,52 @@ let create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t = (** Marker layers *) -let create_marker : Latlng.t -> [ `Marker ] t = - fun latlng -> - let jv_t = Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng |] in +type marker_opt = + | Icon of Icon.t + | Keyboard of bool + | Title of string + | Alt of string + | Z_index_offset of int + | Opacity of float + | Rise_on_hover of bool + | Rise_offset of int + | Pane of string + | Shadow_pane of string + | Bubbling_mouse_events of bool + | Auto_pan_on_focus of bool + +let marker_opt_to_string : marker_opt -> string = function + | Icon _ -> "icon" + | Keyboard _ -> "keyboard" + | Title _ -> "title" + | Alt _ -> "alt" + | Z_index_offset _ -> "zIndexOffset" + | Opacity _ -> "opacity" + | Rise_on_hover _ -> "riseOnHover" + | Rise_offset _ -> "riseOffset" + | Pane _ -> "pane" + | Shadow_pane _ -> "shadowPane" + | Bubbling_mouse_events _ -> "bubblingMouseEvents" + | Auto_pan_on_focus _ -> "autoPanOnFocus" + +let marker_opt_to_jv = function + | Icon icon -> Icon.to_jv icon + | Keyboard b | Rise_on_hover b | Bubbling_mouse_events b | Auto_pan_on_focus b + -> + Jv.of_bool b + | Title s | Alt s | Pane s | Shadow_pane s -> Jv.of_string s + | Z_index_offset i | Rise_offset i -> Jv.of_int i + | Opacity f -> Jv.of_float f + +let create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t = + fun latlng options -> + let l = + Array.of_list + @@ List.map (fun o -> (marker_opt_to_string o, marker_opt_to_jv o)) options + in + let jv_t = + Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng; Jv.obj l |] + in Marker jv_t (** Tile layers *) diff --git a/src/layer.mli b/src/layer.mli index 309d1f5..9f85a0a 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -55,8 +55,22 @@ val create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t (** Marker layers *) +type marker_opt = + | Icon of Icon.t + | Keyboard of bool + | Title of string + | Alt of string + | Z_index_offset of int + | Opacity of float + | Rise_on_hover of bool + | Rise_offset of int + | Pane of string + | Shadow_pane of string + | Bubbling_mouse_events of bool + | Auto_pan_on_focus of bool + (** [create_marker latlng] is a new marker with the same position as latlng *) -val create_marker : Latlng.t -> [ `Marker ] t +val create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t (** Tile layers *) From 502614b9d4f351055705584041552c6089ed5af9 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 09:17:23 +0200 Subject: [PATCH 14/43] add geojson options --- src/layer.ml | 36 +++++++++++++++++++++++++++++++++--- src/layer.mli | 15 +++++++++++++-- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index 7f34d54..b4261aa 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -78,9 +78,39 @@ let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> 'c t -> unit = (** Geojson layers *) -let create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t = - fun ?(options = Jv.null) geojson -> - let jv_t = Jv.call Global.leaflet "geoJSON" [| geojson; options |] in +type geojson_opt = + | Point_to_layer of (Jv.t -> Latlng.t -> unit) + | Style of (Jv.t -> unit) + | On_each_feature of (Jv.t -> [ `Geojson ] t -> unit) + | Filter of (Jv.t -> bool) + | Coords_to_latlng of (Jv.t -> Latlng.t) + | Markers_inherit_options of bool + +let geojson_opt_to_string = function + | Point_to_layer _ -> "pointToLayer" + | Style _ -> "style" + | On_each_feature _ -> "onEachFeature" + | Filter _ -> "filter" + | Coords_to_latlng _ -> "coordsToLatLng" + | Markers_inherit_options _ -> "markersInheritOptions" + +let geojson_opt_to_jv = function + | Markers_inherit_options b -> Jv.of_bool b + | Point_to_layer f -> Jv.repr f + | Style f -> Jv.repr f + | On_each_feature f -> Jv.repr f + | Filter f -> Jv.repr f + | Coords_to_latlng f -> Jv.repr f + +let create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t = + fun geojson options -> + let l = + Array.of_list + @@ List.map + (fun o -> (geojson_opt_to_string o, geojson_opt_to_jv o)) + options + in + let jv_t = Jv.call Global.leaflet "geoJSON" [| geojson; Jv.obj l |] in Geojson jv_t (** Marker layers *) diff --git a/src/layer.mli b/src/layer.mli index 9f85a0a..204afab 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -50,11 +50,21 @@ val on : 'a Event.sub -> ('a Event.t -> 'b) -> 'c t -> unit (** Geojson layers *) +(** type for geojson option, used to create geojson *) +type geojson_opt = + | Point_to_layer of (Jv.t -> Latlng.t -> unit) + | Style of (Jv.t -> unit) + | On_each_feature of (Jv.t -> [ `Geojson ] t -> unit) + | Filter of (Jv.t -> bool) + | Coords_to_latlng of (Jv.t -> Latlng.t) + | Markers_inherit_options of bool + (** [create_geojson geojson] is a new geojson layer *) -val create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t +val create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t (** Marker layers *) +(** type for marker option, used to create marker *) type marker_opt = | Icon of Icon.t | Keyboard of bool @@ -69,7 +79,8 @@ type marker_opt = | Bubbling_mouse_events of bool | Auto_pan_on_focus of bool -(** [create_marker latlng] is a new marker with the same position as latlng *) +(** [create_marker latlng options] is a new marker with the same position as + [latlng] and with options set to [options] *) val create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t (** Tile layers *) From 85e6ad34c66d76c83b8b6884c40adc02353ed6fe Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 10:05:35 +0200 Subject: [PATCH 15/43] add popup options --- src/icon.ml | 4 ++-- src/icon.mli | 2 +- src/layer.ml | 19 ++++++++++++----- src/layer.mli | 2 +- src/popup.ml | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/popup.mli | 27 +++++++++++++++++++++++++ 6 files changed, 101 insertions(+), 9 deletions(-) diff --git a/src/icon.ml b/src/icon.ml index 369c288..c40305d 100644 --- a/src/icon.ml +++ b/src/icon.ml @@ -45,5 +45,5 @@ let opt_to_jv = function let create icon_url options = let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in - let tab = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in - Jv.call Global.leaflet "icon" [| Jv.obj tab |] + let l = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in + Jv.call Global.leaflet "icon" [| Jv.obj l |] diff --git a/src/icon.mli b/src/icon.mli index df3b33e..534c9d9 100644 --- a/src/icon.mli +++ b/src/icon.mli @@ -5,7 +5,7 @@ type t (** [to_jv o] is [o] as {!Jv.t} *) val to_jv : t -> Jv.t -(* type for icon option used to create an icon*) +(** type for icon option used to create an icon*) type opt = | Icon_retina_url of string | Icon_size of Point.t diff --git a/src/layer.ml b/src/layer.ml index b4261aa..fd2042c 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -31,10 +31,16 @@ let remove_from : type kind. Map.t -> kind t -> unit = let (_ : Jv.t) = Jv.call l "removeFrom" [| Map.to_jv map |] in () -let bind_popup : type kind. Brr.El.t -> ?options:Jv.t -> kind t -> unit = - fun el ?(options = Jv.null) -> function - | Basic l | Geojson l | Marker l | Tile l -> - let (_ : Jv.t) = Jv.call l "bindPopup" [| Brr.El.to_jv el; options |] in +let bind_popup : type kind. Brr.El.t -> Popup.opt list -> kind t -> unit = + fun el options -> function + | Basic layer | Geojson layer | Marker layer | Tile layer -> + let l = + Array.of_list + @@ List.map (fun o -> (Popup.opt_to_string o, Popup.opt_to_jv o)) options + in + let (_ : Jv.t) = + Jv.call layer "bindPopup" [| Brr.El.to_jv el; Jv.obj l |] + in () let unbind_popup : type kind. kind t -> unit = function @@ -98,7 +104,10 @@ let geojson_opt_to_jv = function | Markers_inherit_options b -> Jv.of_bool b | Point_to_layer f -> Jv.repr f | Style f -> Jv.repr f - | On_each_feature f -> Jv.repr f + | On_each_feature f -> + (* we need to wrap the Jv.t *) + let f feature jv = jv |> of_jv Geojson |> f feature in + Jv.repr f | Filter f -> Jv.repr f | Coords_to_latlng f -> Jv.repr f diff --git a/src/layer.mli b/src/layer.mli index 204afab..7eaabd2 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -24,7 +24,7 @@ val remove : _ t -> unit val remove_from : Map.t -> _ t -> unit (** [bind_popup popup layer] binds [popup] to [layer] *) -val bind_popup : Brr.El.t -> ?options:Jv.t -> _ t -> unit +val bind_popup : Brr.El.t -> Popup.opt list -> _ t -> unit (** [unbind_popup layer] unbinds the popup bound to [layer] *) val unbind_popup : _ t -> unit diff --git a/src/popup.ml b/src/popup.ml index 5447cd4..f7a1c69 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -21,3 +21,59 @@ let close map = () let of_jv = Fun.id + +type opt = + | Pane of string + | Offset of Point.t + | Max_width of int + | Min_width of int + | Max_height of int + | Auto_pan of bool + | Auto_pan_padding_top_left of Point.t + | Auto_pan_padding_bottom_right of Point.t + | Auto_pan_padding of Point.t + | Keep_in_view of bool + | Close_button of bool + | Auto_close of bool + | Close_on_escape_key of bool + | Close_on_click of bool + | Class_name of string + +let opt_to_string = function + | Pane _ -> "pane" + | Offset _ -> "offset" + | Max_width _ -> "maxWidth" + | Min_width _ -> "minWidth" + | Max_height _ -> "maxHeight" + | Auto_pan _ -> "autoPan" + | Auto_pan_padding_top_left _ -> "autoPanPaddingTopLeft" + | Auto_pan_padding_bottom_right _ -> "autoPanPaddingBottomRight" + | Auto_pan_padding _ -> "autoPanPadding" + | Keep_in_view _ -> "keepInView" + | Close_button _ -> "closeButton" + | Auto_close _ -> "autoClose" + | Close_on_escape_key _ -> "closeOnEscapeKey" + | Close_on_click _ -> "closeOnClick" + | Class_name _ -> "className" + +let opt_to_jv = function + | Offset p + | Auto_pan_padding_top_left p + | Auto_pan_padding_bottom_right p + | Auto_pan_padding p -> + Point.to_jv p + | Max_width i | Min_width i | Max_height i -> Jv.of_int i + | Auto_pan b + | Keep_in_view b + | Close_button b + | Auto_close b + | Close_on_escape_key b + | Close_on_click b -> + Jv.of_bool b + | Pane s | Class_name s -> Jv.of_string s + +let create options = + let l = + Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options + in + Jv.call Global.leaflet "popup" [| Jv.obj l |] diff --git a/src/popup.mli b/src/popup.mli index 9983c5c..da7f27a 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -2,6 +2,24 @@ type t +(** type for popup option used to create an popup*) +type opt = + | Pane of string + | Offset of Point.t + | Max_width of int + | Min_width of int + | Max_height of int + | Auto_pan of bool + | Auto_pan_padding_top_left of Point.t + | Auto_pan_padding_bottom_right of Point.t + | Auto_pan_padding of Point.t + | Keep_in_view of bool + | Close_button of bool + | Auto_close of bool + | Close_on_escape_key of bool + | Close_on_click of bool + | Class_name of string + (** [set_latlng latlng] changes the popup position to the given point*) val set_latlng : Latlng.t -> unit @@ -16,3 +34,12 @@ val close : Map.t -> unit (** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t + +(** [opt_to_string opt] is [opt] as {!string} *) +val opt_to_string : opt -> string + +(** [opt_to_jv opt] is [opt] as {!Jv.t} *) +val opt_to_jv : opt -> Jv.t + +(** [create options] is a new popup setup withs [options] *) +val create : opt list -> t From 8579b9aeede485fd4fd5d0dac25a700c69a9d89d Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 11:04:44 +0200 Subject: [PATCH 16/43] fix Point_to_layer --- src/layer.ml | 6 ++++-- src/layer.mli | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index fd2042c..b18c108 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -85,7 +85,7 @@ let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> 'c t -> unit = (** Geojson layers *) type geojson_opt = - | Point_to_layer of (Jv.t -> Latlng.t -> unit) + | Point_to_layer of (Jv.t -> Latlng.t -> [ `Marker ] t) | Style of (Jv.t -> unit) | On_each_feature of (Jv.t -> [ `Geojson ] t -> unit) | Filter of (Jv.t -> bool) @@ -102,7 +102,9 @@ let geojson_opt_to_string = function let geojson_opt_to_jv = function | Markers_inherit_options b -> Jv.of_bool b - | Point_to_layer f -> Jv.repr f + | Point_to_layer f -> + (* the marker returned by `pointToLayer` is used internally by leaflet so we neet to unwrap it to a Jv.t *) + Jv.repr (fun geojsonpoint latlng -> to_jv @@ f geojsonpoint latlng) | Style f -> Jv.repr f | On_each_feature f -> (* we need to wrap the Jv.t *) diff --git a/src/layer.mli b/src/layer.mli index 7eaabd2..9c7a7cd 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -52,7 +52,7 @@ val on : 'a Event.sub -> ('a Event.t -> 'b) -> 'c t -> unit (** type for geojson option, used to create geojson *) type geojson_opt = - | Point_to_layer of (Jv.t -> Latlng.t -> unit) + | Point_to_layer of (Jv.t -> Latlng.t -> [ `Marker ] t) | Style of (Jv.t -> unit) | On_each_feature of (Jv.t -> [ `Geojson ] t -> unit) | Filter of (Jv.t -> bool) From 9c54ddab973f3a97ed740c3394a6126a062b42f3 Mon Sep 17 00:00:00 2001 From: Swrup Date: Sun, 26 Jun 2022 04:08:53 +0200 Subject: [PATCH 17/43] better Layer.bind_popup and add Map.open/close_popup --- src/layer.ml | 12 +++--------- src/layer.mli | 2 +- src/map.ml | 6 ++++++ src/map.mli | 6 ++++++ src/popup.ml | 10 ++-------- src/popup.mli | 9 +++------ 6 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index b18c108..85a9ce8 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -31,16 +31,10 @@ let remove_from : type kind. Map.t -> kind t -> unit = let (_ : Jv.t) = Jv.call l "removeFrom" [| Map.to_jv map |] in () -let bind_popup : type kind. Brr.El.t -> Popup.opt list -> kind t -> unit = - fun el options -> function +let bind_popup : type kind. Popup.t -> kind t -> unit = + fun popup -> function | Basic layer | Geojson layer | Marker layer | Tile layer -> - let l = - Array.of_list - @@ List.map (fun o -> (Popup.opt_to_string o, Popup.opt_to_jv o)) options - in - let (_ : Jv.t) = - Jv.call layer "bindPopup" [| Brr.El.to_jv el; Jv.obj l |] - in + let (_ : Jv.t) = Jv.call layer "bindPopup" [| Popup.to_jv popup |] in () let unbind_popup : type kind. kind t -> unit = function diff --git a/src/layer.mli b/src/layer.mli index 9c7a7cd..e819d2e 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -24,7 +24,7 @@ val remove : _ t -> unit val remove_from : Map.t -> _ t -> unit (** [bind_popup popup layer] binds [popup] to [layer] *) -val bind_popup : Brr.El.t -> Popup.opt list -> _ t -> unit +val bind_popup : Popup.t -> _ t -> unit (** [unbind_popup layer] unbinds the popup bound to [layer] *) val unbind_popup : _ t -> unit diff --git a/src/map.ml b/src/map.ml index 2f2db23..235510c 100644 --- a/src/map.ml +++ b/src/map.ml @@ -46,3 +46,9 @@ let get_zoom map = Jv.call map "getZoom" [||] |> Jv.to_int let wrap_latlng latlng map = Latlng.of_jv @@ Jv.call map "wrapLatLng" [| Latlng.to_jv latlng |] + +let open_popup popup map = + ignore @@ Jv.call map "openPopup" [| Popup.to_jv popup |] + +let close_popup popup map = + ignore @@ Jv.call map "closePopup" [| Popup.to_jv popup |] diff --git a/src/map.mli b/src/map.mli index c1a7770..db91af9 100644 --- a/src/map.mli +++ b/src/map.mli @@ -47,3 +47,9 @@ val of_jv : Jv.t -> t (** [to_jv o] is [o] as {!Jv.t} *) val to_jv : t -> Jv.t + +(* [open_popup popup map] opens [popup] on [map] *) +val open_popup : Popup.t -> t -> unit + +(* [close_popup popup map] closes [popup] on [map] *) +val close_popup : Popup.t -> t -> unit diff --git a/src/popup.ml b/src/popup.ml index f7a1c69..b2a5072 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -12,16 +12,10 @@ let set_content content = let (_ : Jv.t) = Jv.call popup "setContent" [| Jv.of_string content |] in () -let open_on map = - let (_ : Jv.t) = Jv.call popup "openOn" [| Map.to_jv map |] in - () - -let close map = - let (_ : Jv.t) = Jv.call (Map.to_jv map) "closePopup" [||] in - () - let of_jv = Fun.id +let to_jv = Fun.id + type opt = | Pane of string | Offset of Point.t diff --git a/src/popup.mli b/src/popup.mli index da7f27a..6391cee 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -26,15 +26,12 @@ val set_latlng : Latlng.t -> unit (** [set_content s] changes the popup content to [s]*) val set_content : string -> unit -(** [open_on map] * Adds the popup to [map] and closes the previous one. *) -val open_on : Map.t -> unit - -(** [close map] * closes the popup of [map]*) -val close : Map.t -> unit - (** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t +(** [to_jv o] is [o] as {!Jv.t} *) +val to_jv : t -> Jv.t + (** [opt_to_string opt] is [opt] as {!string} *) val opt_to_string : opt -> string From 9d2aa5b1ff146f85d220deb3919de20f4fe7892b Mon Sep 17 00:00:00 2001 From: Swrup Date: Sun, 26 Jun 2022 05:07:45 +0200 Subject: [PATCH 18/43] better popups --- src/map.ml | 8 ++++++-- src/map.mli | 4 ++-- src/popup.ml | 41 +++++++++++++++++++++++++++++++++++------ src/popup.mli | 20 ++++++++++++++------ 4 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/map.ml b/src/map.ml index 235510c..9dec8d6 100644 --- a/src/map.ml +++ b/src/map.ml @@ -50,5 +50,9 @@ let wrap_latlng latlng map = let open_popup popup map = ignore @@ Jv.call map "openPopup" [| Popup.to_jv popup |] -let close_popup popup map = - ignore @@ Jv.call map "closePopup" [| Popup.to_jv popup |] +let close_popup ~popup map = + ignore + @@ + match popup with + | None -> Jv.call map "closePopup" [||] + | Some popup -> Jv.call map "closePopup" [| Popup.to_jv popup |] diff --git a/src/map.mli b/src/map.mli index db91af9..d1bf3e4 100644 --- a/src/map.mli +++ b/src/map.mli @@ -51,5 +51,5 @@ val to_jv : t -> Jv.t (* [open_popup popup map] opens [popup] on [map] *) val open_popup : Popup.t -> t -> unit -(* [close_popup popup map] closes [popup] on [map] *) -val close_popup : Popup.t -> t -> unit +(* [close_popup opt map] if [opt] is [Some popup] closes [popup] else closes previously opened popup *) +val close_popup : popup:Popup.t option -> t -> unit diff --git a/src/popup.ml b/src/popup.ml index b2a5072..2792e23 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -2,16 +2,18 @@ type t = Jv.t -let popup = Jv.call Global.leaflet "popup" [||] - -let set_latlng latlng = +let set_latlng latlng popup = let (_ : Jv.t) = Jv.call popup "setLatLng" [| Latlng.to_jv latlng |] in () -let set_content content = +let set_content content popup = let (_ : Jv.t) = Jv.call popup "setContent" [| Jv.of_string content |] in () +let set_content_to_el el popup = + let (_ : Jv.t) = Jv.call popup "setContent" [| Brr.El.to_jv el |] in + () + let of_jv = Fun.id let to_jv = Fun.id @@ -66,8 +68,35 @@ let opt_to_jv = function Jv.of_bool b | Pane s | Class_name s -> Jv.of_string s -let create options = +let create content_opt ~latlng options = let l = Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options in - Jv.call Global.leaflet "popup" [| Jv.obj l |] + let popup = Jv.call Global.leaflet "popup" [| Jv.obj l |] in + let popup = + match latlng with + | None -> popup + | Some latlng -> + set_latlng latlng popup; + popup + in + match content_opt with + | None -> popup + | Some content -> + set_content content popup; + popup + +let create_from_el el ~latlng options = + let l = + Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options + in + let popup = Jv.call Global.leaflet "popup" [| Jv.obj l |] in + let popup = + match latlng with + | None -> popup + | Some latlng -> + set_latlng latlng popup; + popup + in + set_content_to_el el popup; + popup diff --git a/src/popup.mli b/src/popup.mli index 6391cee..dae1db8 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -20,11 +20,14 @@ type opt = | Close_on_click of bool | Class_name of string -(** [set_latlng latlng] changes the popup position to the given point*) -val set_latlng : Latlng.t -> unit +(** [set_latlng latlng popup] sets [popup] position to the given point*) +val set_latlng : Latlng.t -> t -> unit -(** [set_content s] changes the popup content to [s]*) -val set_content : string -> unit +(** [set_content s popup] sets [popup] content to [s]*) +val set_content : string -> t -> unit + +(** [set_content_to_el el s] sets [popup] content to [el]*) +val set_content_to_el : Brr.El.t -> t -> unit (** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t @@ -38,5 +41,10 @@ val opt_to_string : opt -> string (** [opt_to_jv opt] is [opt] as {!Jv.t} *) val opt_to_jv : opt -> Jv.t -(** [create options] is a new popup setup withs [options] *) -val create : opt list -> t +(** [create s latlng options] is a new popup setup with [options], position set + to [latlng] and content to [s] *) +val create : string option -> latlng:Latlng.t option -> opt list -> t + +(** [create_from_el el latlng options] is a new popup setup with [options], + position set to [latlng] and content to [el] *) +val create_from_el : Brr.El.t -> latlng:Latlng.t option -> opt list -> t From 96f18396809356ba05f0b2585e1c6b144b118e8d Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 24 Nov 2022 19:21:57 +0100 Subject: [PATCH 19/43] add Icon.create_div --- src/icon.ml | 20 ++++++++++++++++++++ src/icon.mli | 9 +++++++++ 2 files changed, 29 insertions(+) diff --git a/src/icon.ml b/src/icon.ml index c40305d..f8e1bb5 100644 --- a/src/icon.ml +++ b/src/icon.ml @@ -4,6 +4,8 @@ type t = Jv.t let to_jv = Fun.id +let of_jv = Fun.id + type opt = | Icon_retina_url of string | Icon_size of Point.t @@ -47,3 +49,21 @@ let create icon_url options = let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in let l = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in Jv.call Global.leaflet "icon" [| Jv.obj l |] + +let create_div ~html ~bg_pos options = + let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in + let div_options = + let html = + match html with + | None -> [] + | Some html -> [ ("html", Jv.of_string html) ] + in + let bg_pos = + match bg_pos with + | None -> [] + | Some bg_pos -> [ ("bgPos", Point.to_jv bg_pos) ] + in + html @ bg_pos + in + let l = Array.of_list @@ div_options @ l in + Jv.call Global.leaflet "divIcon" [| Jv.obj l |] diff --git a/src/icon.mli b/src/icon.mli index 534c9d9..d7734dd 100644 --- a/src/icon.mli +++ b/src/icon.mli @@ -5,6 +5,9 @@ type t (** [to_jv o] is [o] as {!Jv.t} *) val to_jv : t -> Jv.t +(** [of_jv o] is [o] as {!Icon.t} *) +val of_jv : Jv.t -> t + (** type for icon option used to create an icon*) type opt = | Icon_retina_url of string @@ -22,3 +25,9 @@ type opt = (** [create icon_url options] Creates an icon instance with the given [options], and the required `iconUrl` option set to [icon_url] *) val create : string -> opt list -> t + +(** [create_div ~html ~bg_pos options] Creates an DivIcon instance with the + given [options], [bg_pos] is the optional relative position of the + background, in pixels [html] is custom HTML code to put inside the div + element, empty by default. *) +val create_div : html:string option -> bg_pos:Point.t option -> opt list -> t From d0c4f09b11fd36ba319f8f9e03650f1969b7043e Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 24 Nov 2022 19:22:18 +0100 Subject: [PATCH 20/43] more marker function --- src/layer.ml | 67 ++++++++++++++++++++++++++++++++++++--------------- src/layer.mli | 28 +++++++++++++++++---- 2 files changed, 70 insertions(+), 25 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index 85a9ce8..f98de08 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -118,7 +118,30 @@ let create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t = let jv_t = Jv.call Global.leaflet "geoJSON" [| geojson; Jv.obj l |] in Geojson jv_t +(** Tile layers *) + +let create_tile_osm : string option -> [ `Tile ] t = + fun url -> + let url = + Option.value url + ~default:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" + in + let jv_t = + Jv.call Global.leaflet "tileLayer" + [| Jv.of_string url + ; Jv.obj + [| ( "attribution" + , Jv.of_string + "© OpenStreetMap \ + contributors" ) + |] + |] + in + Tile jv_t + (** Marker layers *) +(* TODO make a Marker module? *) type marker_opt = | Icon of Icon.t @@ -168,24 +191,28 @@ let create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t = in Marker jv_t -(** Tile layers *) +let get_latlng : [ `Marker ] t -> Latlng.t = function + | Marker marker -> Jv.call marker "getLatLng" [||] |> Latlng.of_jv -let create_tile_osm : string option -> [ `Tile ] t = - fun url -> - let url = - Option.value url - ~default:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" - in - let jv_t = - Jv.call Global.leaflet "tileLayer" - [| Jv.of_string url - ; Jv.obj - [| ( "attribution" - , Jv.of_string - "© OpenStreetMap \ - contributors" ) - |] - |] - in - Tile jv_t +let set_latlng latlng : [ `Marker ] t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setLatLng" [| Latlng.to_jv latlng |] in + () + +let set_z_index_offset z_index : [ `Marker ] t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setZIndexOffset" [| Jv.of_int z_index |] in + () + +let get_icon : [ `Marker ] t -> Icon.t = function + | Marker marker -> Jv.call marker "getIcon" [||] |> Icon.of_jv + +let set_icon icon : [ `Marker ] t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setIcon" [| Icon.to_jv icon |] in + () + +let set_opacity opacity : [ `Marker ] t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setOpacity" [| Jv.of_int opacity |] in + () diff --git a/src/layer.mli b/src/layer.mli index e819d2e..84586d7 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -62,6 +62,13 @@ type geojson_opt = (** [create_geojson geojson] is a new geojson layer *) val create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t +(** Tile layers *) + +(** [create_tile_osm Some(url)] is a new tile layer with tile server specified + by [url]. Tile server default to [openstreetmap.org]. See + {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) +val create_tile_osm : string option -> [ `Tile ] t + (** Marker layers *) (** type for marker option, used to create marker *) @@ -83,9 +90,20 @@ type marker_opt = [latlng] and with options set to [options] *) val create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t -(** Tile layers *) +(** Returns the current geographical position of the marker. *) +val get_latlng : [ `Marker ] t -> Latlng.t -(** [create_tile_osm Some(url)] is a new tile layer with tile server specified - by [url]. Tile server default to [openstreetmap.org]. See - {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) -val create_tile_osm : string option -> [ `Tile ] t +(** Changes the marker position to the given point. *) +val set_latlng : Latlng.t -> [ `Marker ] t -> unit + +(** Changes the zIndex offset of the marker. *) +val set_z_index_offset : int -> [ `Marker ] t -> unit + +(** Returns the current icon used by the marker *) +val get_icon : [ `Marker ] t -> Icon.t + +(** Changes the marker icon. *) +val set_icon : Icon.t -> [ `Marker ] t -> unit + +(** Changes the opacity of the marker. *) +val set_opacity : int -> [ `Marker ] t -> unit From 800d42132c66e37b84152d6871d85a2892649545 Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 31 Dec 2022 01:58:10 +0100 Subject: [PATCH 21/43] fix doc --- src/map.mli | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map.mli b/src/map.mli index d1bf3e4..5d7a912 100644 --- a/src/map.mli +++ b/src/map.mli @@ -2,7 +2,7 @@ type t -(** [create id] creates a map on the
with DOM id [id]. To have a +(** [create_on id] creates a map on the
with DOM id [id]. To have a functional map you will need to add a tile layer to it. *) val create_on : ?options:Jv.t -> string -> t From d6852c90992e398f77f96e45db5ced830d7fafba Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 31 Dec 2022 01:59:30 +0100 Subject: [PATCH 22/43] update ocamlformat --- .ocamlformat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ocamlformat b/.ocamlformat index cec2d50..c54116a 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version=0.22.4 +version=0.24.1 assignment-operator=end-line break-cases=fit break-fun-decl=wrap From 4413b178a1e39edf1454307f13b1d79639b4b9cf Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 31 Dec 2022 02:45:32 +0100 Subject: [PATCH 23/43] small popup change --- src/map.mli | 2 +- src/popup.ml | 4 ++-- src/popup.mli | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/map.mli b/src/map.mli index 5d7a912..ede2965 100644 --- a/src/map.mli +++ b/src/map.mli @@ -48,7 +48,7 @@ val of_jv : Jv.t -> t (** [to_jv o] is [o] as {!Jv.t} *) val to_jv : t -> Jv.t -(* [open_popup popup map] opens [popup] on [map] *) +(* [open_popup popup map] opens [popup] on [map]; Opens the specified popup while closing the previously opened (to make sure only one is opened at one time for usability). *) val open_popup : Popup.t -> t -> unit (* [close_popup opt map] if [opt] is [Some popup] closes [popup] else closes previously opened popup *) diff --git a/src/popup.ml b/src/popup.ml index 2792e23..3960a81 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -68,7 +68,7 @@ let opt_to_jv = function Jv.of_bool b | Pane s | Class_name s -> Jv.of_string s -let create content_opt ~latlng options = +let create ~content ~latlng options = let l = Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options in @@ -80,7 +80,7 @@ let create content_opt ~latlng options = set_latlng latlng popup; popup in - match content_opt with + match content with | None -> popup | Some content -> set_content content popup; diff --git a/src/popup.mli b/src/popup.mli index dae1db8..d099745 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -41,9 +41,9 @@ val opt_to_string : opt -> string (** [opt_to_jv opt] is [opt] as {!Jv.t} *) val opt_to_jv : opt -> Jv.t -(** [create s latlng options] is a new popup setup with [options], position set - to [latlng] and content to [s] *) -val create : string option -> latlng:Latlng.t option -> opt list -> t +(** [create ~content ~latlng options] is a new popup setup with [options], + position set to [latlng] and content to [s] *) +val create : content:string option -> latlng:Latlng.t option -> opt list -> t (** [create_from_el el latlng options] is a new popup setup with [options], position set to [latlng] and content to [el] *) From 82f00157614796215683762a3f34f5775ebaae0d Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 29 Jan 2024 20:27:37 +0100 Subject: [PATCH 24/43] -> Latlng.create ~lat ~lng --- .ocamlformat | 2 +- example/main.ml | 2 +- src/latlng.ml | 2 +- src/latlng.mli | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.ocamlformat b/.ocamlformat index c54116a..74ae9c5 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version=0.24.1 +version=0.26.1 assignment-operator=end-line break-cases=fit break-fun-decl=wrap diff --git a/example/main.ml b/example/main.ml index 43b9fcd..4a90920 100644 --- a/example/main.ml +++ b/example/main.ml @@ -8,5 +8,5 @@ let () = Leaflet.Layer.add_to map osm_layer; (* set view *) - let latlng = Leaflet.Latlng.create 40.71 (-74.0) in + let latlng = Leaflet.Latlng.create ~lat:40.71 ~lng:(-74.0) in ignore @@ Leaflet.Map.set_view latlng ~zoom:(Some 13) map diff --git a/src/latlng.ml b/src/latlng.ml index 400200b..89cd3b8 100644 --- a/src/latlng.ml +++ b/src/latlng.ml @@ -2,7 +2,7 @@ type t = Jv.t -let create lat lng = +let create ~lat ~lng = Jv.call Global.leaflet "latLng" [| Jv.of_float lat; Jv.of_float lng |] let lat latlng = Jv.get latlng "lat" |> Jv.to_float diff --git a/src/latlng.mli b/src/latlng.mli index 120d165..3bff192 100644 --- a/src/latlng.mli +++ b/src/latlng.mli @@ -4,7 +4,7 @@ type t (** [create lat lng] is an object representing a geographical point with the given latitude and longitude *) -val create : float -> float -> t +val create : lat:float -> lng:float -> t (** [lat o] is the latitude of [o] *) val lat : t -> float From ce9cdc206dc890cb282e1df923a23eb2494f296e Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 29 Jan 2024 22:07:41 +0100 Subject: [PATCH 25/43] move marker to separate module --- src/dune | 2 +- src/layer.ml | 77 ------------------------------------------------- src/layer.mli | 39 ------------------------- src/marker.ml | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/marker.mli | 38 ++++++++++++++++++++++++ 5 files changed, 117 insertions(+), 117 deletions(-) create mode 100644 src/marker.ml create mode 100644 src/marker.mli diff --git a/src/dune b/src/dune index 52d85ee..c29d930 100644 --- a/src/dune +++ b/src/dune @@ -1,6 +1,6 @@ (library (public_name leaflet) - (modules event global latlng layer map popup point icon) + (modules event global latlng layer map marker popup point icon) (private_modules global) (libraries brr) (js_of_ocaml diff --git a/src/layer.ml b/src/layer.ml index f98de08..e6ac275 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -139,80 +139,3 @@ let create_tile_osm : string option -> [ `Tile ] t = |] in Tile jv_t - -(** Marker layers *) -(* TODO make a Marker module? *) - -type marker_opt = - | Icon of Icon.t - | Keyboard of bool - | Title of string - | Alt of string - | Z_index_offset of int - | Opacity of float - | Rise_on_hover of bool - | Rise_offset of int - | Pane of string - | Shadow_pane of string - | Bubbling_mouse_events of bool - | Auto_pan_on_focus of bool - -let marker_opt_to_string : marker_opt -> string = function - | Icon _ -> "icon" - | Keyboard _ -> "keyboard" - | Title _ -> "title" - | Alt _ -> "alt" - | Z_index_offset _ -> "zIndexOffset" - | Opacity _ -> "opacity" - | Rise_on_hover _ -> "riseOnHover" - | Rise_offset _ -> "riseOffset" - | Pane _ -> "pane" - | Shadow_pane _ -> "shadowPane" - | Bubbling_mouse_events _ -> "bubblingMouseEvents" - | Auto_pan_on_focus _ -> "autoPanOnFocus" - -let marker_opt_to_jv = function - | Icon icon -> Icon.to_jv icon - | Keyboard b | Rise_on_hover b | Bubbling_mouse_events b | Auto_pan_on_focus b - -> - Jv.of_bool b - | Title s | Alt s | Pane s | Shadow_pane s -> Jv.of_string s - | Z_index_offset i | Rise_offset i -> Jv.of_int i - | Opacity f -> Jv.of_float f - -let create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t = - fun latlng options -> - let l = - Array.of_list - @@ List.map (fun o -> (marker_opt_to_string o, marker_opt_to_jv o)) options - in - let jv_t = - Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng; Jv.obj l |] - in - Marker jv_t - -let get_latlng : [ `Marker ] t -> Latlng.t = function - | Marker marker -> Jv.call marker "getLatLng" [||] |> Latlng.of_jv - -let set_latlng latlng : [ `Marker ] t -> unit = function - | Marker marker -> - let (_ : Jv.t) = Jv.call marker "setLatLng" [| Latlng.to_jv latlng |] in - () - -let set_z_index_offset z_index : [ `Marker ] t -> unit = function - | Marker marker -> - let (_ : Jv.t) = Jv.call marker "setZIndexOffset" [| Jv.of_int z_index |] in - () - -let get_icon : [ `Marker ] t -> Icon.t = function - | Marker marker -> Jv.call marker "getIcon" [||] |> Icon.of_jv - -let set_icon icon : [ `Marker ] t -> unit = function - | Marker marker -> - let (_ : Jv.t) = Jv.call marker "setIcon" [| Icon.to_jv icon |] in - () - -let set_opacity opacity : [ `Marker ] t -> unit = function - | Marker marker -> - let (_ : Jv.t) = Jv.call marker "setOpacity" [| Jv.of_int opacity |] in - () diff --git a/src/layer.mli b/src/layer.mli index 84586d7..10cedc2 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -68,42 +68,3 @@ val create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t by [url]. Tile server default to [openstreetmap.org]. See {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) val create_tile_osm : string option -> [ `Tile ] t - -(** Marker layers *) - -(** type for marker option, used to create marker *) -type marker_opt = - | Icon of Icon.t - | Keyboard of bool - | Title of string - | Alt of string - | Z_index_offset of int - | Opacity of float - | Rise_on_hover of bool - | Rise_offset of int - | Pane of string - | Shadow_pane of string - | Bubbling_mouse_events of bool - | Auto_pan_on_focus of bool - -(** [create_marker latlng options] is a new marker with the same position as - [latlng] and with options set to [options] *) -val create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t - -(** Returns the current geographical position of the marker. *) -val get_latlng : [ `Marker ] t -> Latlng.t - -(** Changes the marker position to the given point. *) -val set_latlng : Latlng.t -> [ `Marker ] t -> unit - -(** Changes the zIndex offset of the marker. *) -val set_z_index_offset : int -> [ `Marker ] t -> unit - -(** Returns the current icon used by the marker *) -val get_icon : [ `Marker ] t -> Icon.t - -(** Changes the marker icon. *) -val set_icon : Icon.t -> [ `Marker ] t -> unit - -(** Changes the opacity of the marker. *) -val set_opacity : int -> [ `Marker ] t -> unit diff --git a/src/marker.ml b/src/marker.ml new file mode 100644 index 0000000..16a99c0 --- /dev/null +++ b/src/marker.ml @@ -0,0 +1,78 @@ +(** Marker layers *) +include Layer + +type t = [ `Marker ] Layer.t + +type marker_opt = + | Icon of Icon.t + | Keyboard of bool + | Title of string + | Alt of string + | Z_index_offset of int + | Opacity of float + | Rise_on_hover of bool + | Rise_offset of int + | Pane of string + | Shadow_pane of string + | Bubbling_mouse_events of bool + | Auto_pan_on_focus of bool + +let marker_opt_to_string : marker_opt -> string = function + | Icon _ -> "icon" + | Keyboard _ -> "keyboard" + | Title _ -> "title" + | Alt _ -> "alt" + | Z_index_offset _ -> "zIndexOffset" + | Opacity _ -> "opacity" + | Rise_on_hover _ -> "riseOnHover" + | Rise_offset _ -> "riseOffset" + | Pane _ -> "pane" + | Shadow_pane _ -> "shadowPane" + | Bubbling_mouse_events _ -> "bubblingMouseEvents" + | Auto_pan_on_focus _ -> "autoPanOnFocus" + +let marker_opt_to_jv = function + | Icon icon -> Icon.to_jv icon + | Keyboard b | Rise_on_hover b | Bubbling_mouse_events b | Auto_pan_on_focus b + -> + Jv.of_bool b + | Title s | Alt s | Pane s | Shadow_pane s -> Jv.of_string s + | Z_index_offset i | Rise_offset i -> Jv.of_int i + | Opacity f -> Jv.of_float f + +let create_marker : Latlng.t -> marker_opt list -> t = + fun latlng options -> + let l = + Array.of_list + @@ List.map (fun o -> (marker_opt_to_string o, marker_opt_to_jv o)) options + in + let jv_t = + Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng; Jv.obj l |] + in + Marker jv_t + +let get_latlng : t -> Latlng.t = function + | Marker marker -> Jv.call marker "getLatLng" [||] |> Latlng.of_jv + +let set_latlng latlng : t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setLatLng" [| Latlng.to_jv latlng |] in + () + +let set_z_index_offset z_index : t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setZIndexOffset" [| Jv.of_int z_index |] in + () + +let get_icon : t -> Icon.t = function + | Marker marker -> Jv.call marker "getIcon" [||] |> Icon.of_jv + +let set_icon icon : t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setIcon" [| Icon.to_jv icon |] in + () + +let set_opacity opacity : t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setOpacity" [| Jv.of_int opacity |] in + () diff --git a/src/marker.mli b/src/marker.mli new file mode 100644 index 0000000..538ac95 --- /dev/null +++ b/src/marker.mli @@ -0,0 +1,38 @@ +type t = [ `Marker ] Layer.t + +(** type for marker option, used to create marker *) +type marker_opt = + | Icon of Icon.t + | Keyboard of bool + | Title of string + | Alt of string + | Z_index_offset of int + | Opacity of float + | Rise_on_hover of bool + | Rise_offset of int + | Pane of string + | Shadow_pane of string + | Bubbling_mouse_events of bool + | Auto_pan_on_focus of bool + +(** [create_marker latlng options] is a new marker with the same position as + [latlng] and with options set to [options] *) +val create_marker : Latlng.t -> marker_opt list -> t + +(** Returns the current geographical position of the marker. *) +val get_latlng : t -> Latlng.t + +(** Changes the marker position to the given point. *) +val set_latlng : Latlng.t -> t -> unit + +(** Changes the zIndex offset of the marker. *) +val set_z_index_offset : int -> t -> unit + +(** Returns the current icon used by the marker *) +val get_icon : t -> Icon.t + +(** Changes the marker icon. *) +val set_icon : Icon.t -> t -> unit + +(** Changes the opacity of the marker. *) +val set_opacity : int -> t -> unit From 3332d0fb7c86888d778f6c94a18ede1346a5006a Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 29 Jan 2024 22:08:10 +0100 Subject: [PATCH 26/43] add Icon.set_default_image_path --- src/icon.ml | 5 +++++ src/icon.mli | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/icon.ml b/src/icon.ml index f8e1bb5..4ed4972 100644 --- a/src/icon.ml +++ b/src/icon.ml @@ -67,3 +67,8 @@ let create_div ~html ~bg_pos options = in let l = Array.of_list @@ div_options @ l in Jv.call Global.leaflet "divIcon" [| Jv.obj l |] + +let set_default_image_path s = + let icon = Jv.get Global.leaflet "Icon" in + let icon_default = Jv.get icon "Default" in + Jv.set icon_default "imagePath" (Jv.of_string s) diff --git a/src/icon.mli b/src/icon.mli index d7734dd..451b51f 100644 --- a/src/icon.mli +++ b/src/icon.mli @@ -31,3 +31,6 @@ val create : string -> opt list -> t background, in pixels [html] is custom HTML code to put inside the div element, empty by default. *) val create_div : html:string option -> bg_pos:Point.t option -> opt list -> t + +(** Sets the path of the default icon *) +val set_default_image_path : string -> unit From ccddd550f962949111bd7743365bfe3c7fa3a95a Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 29 Jan 2024 22:49:31 +0100 Subject: [PATCH 27/43] add tile_layer_opt; untested --- example/main.ml | 2 +- src/layer.ml | 73 +++++++++++++++++++++++++++++++++++++++---------- src/layer.mli | 22 +++++++++++++-- 3 files changed, 78 insertions(+), 19 deletions(-) diff --git a/example/main.ml b/example/main.ml index 4a90920..abfe34a 100644 --- a/example/main.ml +++ b/example/main.ml @@ -4,7 +4,7 @@ let map = Leaflet.Map.create_on "map" (* setup map *) let () = (* set osm layer *) - let osm_layer = Leaflet.Layer.create_tile_osm None in + let osm_layer = Leaflet.Layer.create_tile_osm [] in Leaflet.Layer.add_to map osm_layer; (* set view *) diff --git a/src/layer.ml b/src/layer.ml index e6ac275..fa9dc0d 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -120,22 +120,65 @@ let create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t = (** Tile layers *) -let create_tile_osm : string option -> [ `Tile ] t = - fun url -> - let url = - Option.value url - ~default:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" +type tile_layer_opt = + | Min_zoom of int + | Max_zoom of int + | Subdomains of string array + | Error_tile_url of string + | Zoom_offset of int + | Tms of bool + | Zoom_reverse of bool + | Detect_retina of bool + (* TODO allow string for those two + "Whether the crossOrigin attribute will be added to the tiles. If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data. Refer to CORS Settings for valid String values." + *) + | Cross_origin of bool + | Referrer_policy of bool + +let tile_layer_opt_to_string = function + | Min_zoom _ -> "minZoom" + | Max_zoom _ -> "maxZoom" + | Subdomains _ -> "subdomains" + | Error_tile_url _ -> "errorTileUrl" + | Zoom_offset _ -> "zoomOffset" + | Tms _ -> "tms" + | Zoom_reverse _ -> "zoomReverse" + | Detect_retina _ -> "detectRetina" + | Cross_origin _ -> "crossOrigin" + | Referrer_policy _ -> "referrerPolicy" + +let tile_layer_opt_to_jv = function + | Min_zoom o | Max_zoom o | Zoom_offset o -> Jv.of_int o + | Tms o + | Zoom_reverse o + | Detect_retina o + | Cross_origin o + | Referrer_policy o -> + Jv.of_bool o + | Error_tile_url o -> Jv.of_string o + | Subdomains o -> Jv.of_array Jv.of_string o + +let create_tile : + string -> attribution:string -> tile_layer_opt list -> [ `Tile ] t = + fun url ~attribution options -> + let arr = + Array.of_list + @@ ("attribution", Jv.of_string attribution) + :: List.map + (fun o -> (tile_layer_opt_to_string o, tile_layer_opt_to_jv o)) + options in let jv_t = - Jv.call Global.leaflet "tileLayer" - [| Jv.of_string url - ; Jv.obj - [| ( "attribution" - , Jv.of_string - "© OpenStreetMap \ - contributors" ) - |] - |] + Jv.call Global.leaflet "tileLayer" [| Jv.of_string url; Jv.obj arr |] in Tile jv_t + +let create_tile_osm : tile_layer_opt list -> [ `Tile ] t = + fun options -> + let url = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" in + let attribution = + "© OpenStreetMap \ + contributors" + in + create_tile url ~attribution options diff --git a/src/layer.mli b/src/layer.mli index 10cedc2..bd5513d 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -64,7 +64,23 @@ val create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t (** Tile layers *) -(** [create_tile_osm Some(url)] is a new tile layer with tile server specified - by [url]. Tile server default to [openstreetmap.org]. See +type tile_layer_opt = + | Min_zoom of int + | Max_zoom of int + | Subdomains of string array + | Error_tile_url of string + | Zoom_offset of int + | Tms of bool + | Zoom_reverse of bool + | Detect_retina of bool + | Cross_origin of bool + | Referrer_policy of bool + +(** [create_tile url attribution opts] create a new tile layer *) +val create_tile : + string -> attribution:string -> tile_layer_opt list -> [ `Tile ] t + +(** [create_tile_osm opts] create a new tile layer with tile server and + attribution set to [openstreetmap.org]. See {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) -val create_tile_osm : string option -> [ `Tile ] t +val create_tile_osm : tile_layer_opt list -> [ `Tile ] t From b8344b172a1a1e0b7019bc84d0a08c1e91c1b8b3 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 29 Jan 2024 23:05:24 +0100 Subject: [PATCH 28/43] cleanup Marker --- src/marker.ml | 11 +++++------ src/marker.mli | 8 ++++---- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/marker.ml b/src/marker.ml index 16a99c0..93ebd05 100644 --- a/src/marker.ml +++ b/src/marker.ml @@ -3,7 +3,7 @@ include Layer type t = [ `Marker ] Layer.t -type marker_opt = +type opt = | Icon of Icon.t | Keyboard of bool | Title of string @@ -17,7 +17,7 @@ type marker_opt = | Bubbling_mouse_events of bool | Auto_pan_on_focus of bool -let marker_opt_to_string : marker_opt -> string = function +let opt_to_string : opt -> string = function | Icon _ -> "icon" | Keyboard _ -> "keyboard" | Title _ -> "title" @@ -31,7 +31,7 @@ let marker_opt_to_string : marker_opt -> string = function | Bubbling_mouse_events _ -> "bubblingMouseEvents" | Auto_pan_on_focus _ -> "autoPanOnFocus" -let marker_opt_to_jv = function +let opt_to_jv = function | Icon icon -> Icon.to_jv icon | Keyboard b | Rise_on_hover b | Bubbling_mouse_events b | Auto_pan_on_focus b -> @@ -40,11 +40,10 @@ let marker_opt_to_jv = function | Z_index_offset i | Rise_offset i -> Jv.of_int i | Opacity f -> Jv.of_float f -let create_marker : Latlng.t -> marker_opt list -> t = +let create : Latlng.t -> opt list -> t = fun latlng options -> let l = - Array.of_list - @@ List.map (fun o -> (marker_opt_to_string o, marker_opt_to_jv o)) options + Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options in let jv_t = Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng; Jv.obj l |] diff --git a/src/marker.mli b/src/marker.mli index 538ac95..ebb8096 100644 --- a/src/marker.mli +++ b/src/marker.mli @@ -1,7 +1,7 @@ type t = [ `Marker ] Layer.t (** type for marker option, used to create marker *) -type marker_opt = +type opt = | Icon of Icon.t | Keyboard of bool | Title of string @@ -15,9 +15,9 @@ type marker_opt = | Bubbling_mouse_events of bool | Auto_pan_on_focus of bool -(** [create_marker latlng options] is a new marker with the same position as - [latlng] and with options set to [options] *) -val create_marker : Latlng.t -> marker_opt list -> t +(** [create latlng options] is a new marker with the same position as [latlng] + and with options set to [options] *) +val create : Latlng.t -> opt list -> t (** Returns the current geographical position of the marker. *) val get_latlng : t -> Latlng.t From 92faca6a92687aa1d389702942f1c8f9e5ee780b Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 30 Jan 2024 00:20:36 +0100 Subject: [PATCH 29/43] add more options to tile_layer --- src/layer.ml | 57 ++++++++++++++++++++++++++++++++++++++++++++------- src/layer.mli | 13 ++++++++++++ 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index fa9dc0d..ec9bb68 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -129,11 +129,25 @@ type tile_layer_opt = | Tms of bool | Zoom_reverse of bool | Detect_retina of bool - (* TODO allow string for those two - "Whether the crossOrigin attribute will be added to the tiles. If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data. Refer to CORS Settings for valid String values." - *) - | Cross_origin of bool + | (* TODO allow string for those two + "Whether the crossOrigin attribute will be added to the tiles. If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data. Refer to CORS Settings for valid String values." + *) + Cross_origin of bool | Referrer_policy of bool + | (* GridLayer options *) + Tile_size of Point.t + | Opacity of float + | Update_when_idle of bool + | Update_when_zooming of bool + | Update_interval of int + | Z_index of int + | Bounds of (* LatLngBounds *) Latlng.t * Latlng.t + | Max_native_zoom of int + | Min_native_zoom of int + | No_wrap of bool + | Pane of string + | Class_name of string + | Keep_buffer of int let tile_layer_opt_to_string = function | Min_zoom _ -> "minZoom" @@ -146,17 +160,46 @@ let tile_layer_opt_to_string = function | Detect_retina _ -> "detectRetina" | Cross_origin _ -> "crossOrigin" | Referrer_policy _ -> "referrerPolicy" + | Tile_size _ -> "tileSize" + | Opacity _ -> "opacity" + | Update_when_idle _ -> "updateWhenIdle" + | Update_when_zooming _ -> "updateWhenZooming" + | Update_interval _ -> "updateInterval" + | Z_index _ -> "zIndex" + | Bounds _ -> "bounds" + | Max_native_zoom _ -> "maxNativeZoom" + | Min_native_zoom _ -> "minNativeZoom" + | No_wrap _ -> "noWrap" + | Pane _ -> "pane" + | Class_name _ -> "className" + | Keep_buffer _ -> "keepBuffer" let tile_layer_opt_to_jv = function - | Min_zoom o | Max_zoom o | Zoom_offset o -> Jv.of_int o + | Min_zoom o + | Max_zoom o + | Zoom_offset o + | Update_interval o + | Z_index o + | Keep_buffer o + | Min_native_zoom o + | Max_native_zoom o -> + Jv.of_int o | Tms o | Zoom_reverse o | Detect_retina o | Cross_origin o - | Referrer_policy o -> + | Referrer_policy o + | Update_when_idle o + | Update_when_zooming o + | No_wrap o -> Jv.of_bool o - | Error_tile_url o -> Jv.of_string o + | Error_tile_url o | Pane o | Class_name o -> Jv.of_string o | Subdomains o -> Jv.of_array Jv.of_string o + | Opacity o -> Jv.of_float o + | Tile_size o -> Point.to_jv o + | Bounds (a, b) -> + (* create the actual LatlngBounds from the pair *) + Jv.call Global.leaflet "latLngBounds" [| Latlng.to_jv a; Latlng.to_jv b |] let create_tile : string -> attribution:string -> tile_layer_opt list -> [ `Tile ] t = diff --git a/src/layer.mli b/src/layer.mli index bd5513d..5c28258 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -75,6 +75,19 @@ type tile_layer_opt = | Detect_retina of bool | Cross_origin of bool | Referrer_policy of bool + | Tile_size of Point.t + | Opacity of float + | Update_when_idle of bool + | Update_when_zooming of bool + | Update_interval of int + | Z_index of int + | Bounds of (* LatLngBounds *) Latlng.t * Latlng.t + | Max_native_zoom of int + | Min_native_zoom of int + | No_wrap of bool + | Pane of string + | Class_name of string + | Keep_buffer of int (** [create_tile url attribution opts] create a new tile layer *) val create_tile : From 3d91ee4ae6e4901c7d7ce1b059d21e6a5fb58d98 Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 30 Jan 2024 00:48:37 +0100 Subject: [PATCH 30/43] add polyline layer --- src/layer.ml | 29 ++++++++++++++++++++--------- src/layer.mli | 5 +++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index ec9bb68..12c35c3 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -5,59 +5,61 @@ type _ t = | Geojson : Jv.t -> [> `Geojson ] t | Marker : Jv.t -> [> `Marker ] t | Tile : Jv.t -> [> `Tile ] t + | Vector : Jv.t -> [> `Vector ] t type _ sub = | Basic : [> `Basic ] sub | Geojson : [> `Geojson ] sub | Marker : [> `Marker ] sub | Tile : [> `Tile ] sub + | Vector : [> `Vector ] sub (** Basic layers *) let add_to : type kind. Map.t -> kind t -> unit = fun map -> function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "addTo" [| Map.to_jv map |] in () let remove : type kind. kind t -> unit = function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "remove" [||] in () let remove_from : type kind. Map.t -> kind t -> unit = fun map -> function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "removeFrom" [| Map.to_jv map |] in () let bind_popup : type kind. Popup.t -> kind t -> unit = fun popup -> function - | Basic layer | Geojson layer | Marker layer | Tile layer -> + | Basic layer | Geojson layer | Marker layer | Tile layer | Vector layer -> let (_ : Jv.t) = Jv.call layer "bindPopup" [| Popup.to_jv popup |] in () let unbind_popup : type kind. kind t -> unit = function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "unbindPopup" [||] in () let open_popup : type kind. kind t -> unit = function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "openPopup" [||] in () let close_popup : type kind. kind t -> unit = function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "closePopup" [||] in () let get_popup : type kind. kind t -> Popup.t = function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> Jv.call l "getPopup" [||] |> Popup.of_jv let to_jv : type kind. kind t -> Jv.t = function - | Basic l | Geojson l | Marker l | Tile l -> l + | Basic l | Geojson l | Marker l | Tile l | Vector l -> l let of_jv : type kind. kind sub -> Jv.t -> kind t = fun tag l -> @@ -66,6 +68,7 @@ let of_jv : type kind. kind sub -> Jv.t -> kind t = | Geojson -> Geojson l | Marker -> Marker l | Tile -> Tile l + | Vector -> Vector l let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> 'c t -> unit = fun event handler layer -> @@ -225,3 +228,11 @@ let create_tile_osm : tile_layer_opt list -> [ `Tile ] t = contributors" in create_tile url ~attribution options + +(* Vector Layers *) + +let create_polyline : Latlng.t list -> [ `Vector ] t = + fun l -> + let l = Jv.of_list Latlng.to_jv l in + let jv_t = Jv.call Global.leaflet "polyline" [| l |] in + Vector jv_t diff --git a/src/layer.mli b/src/layer.mli index 5c28258..1f34363 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -5,12 +5,14 @@ type _ t = | Geojson : Jv.t -> [> `Geojson ] t | Marker : Jv.t -> [> `Marker ] t | Tile : Jv.t -> [> `Tile ] t + | Vector : Jv.t -> [> `Vector ] t type _ sub = | Basic : [> `Basic ] sub | Geojson : [> `Geojson ] sub | Marker : [> `Marker ] sub | Tile : [> `Tile ] sub + | Vector : [> `Vector ] sub (** Basic layers *) @@ -97,3 +99,6 @@ val create_tile : attribution set to [openstreetmap.org]. See {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) val create_tile_osm : tile_layer_opt list -> [ `Tile ] t + +(** [create_polyline l] create a polyline layer from [l] *) +val create_polyline : Latlng.t list -> [ `Vector ] t From bbd19599cd0f87946ddfac8860296536fb3b4670 Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 30 Jan 2024 16:55:19 +0100 Subject: [PATCH 31/43] list -> array --- example/main.ml | 2 +- src/icon.ml | 10 +++++----- src/icon.mli | 4 ++-- src/layer.ml | 25 +++++++++++-------------- src/layer.mli | 8 ++++---- src/marker.ml | 6 ++---- src/marker.mli | 2 +- src/popup.ml | 8 ++------ src/popup.mli | 4 ++-- 9 files changed, 30 insertions(+), 39 deletions(-) diff --git a/example/main.ml b/example/main.ml index abfe34a..5fbe7c4 100644 --- a/example/main.ml +++ b/example/main.ml @@ -4,7 +4,7 @@ let map = Leaflet.Map.create_on "map" (* setup map *) let () = (* set osm layer *) - let osm_layer = Leaflet.Layer.create_tile_osm [] in + let osm_layer = Leaflet.Layer.create_tile_osm [||] in Leaflet.Layer.add_to map osm_layer; (* set view *) diff --git a/src/icon.ml b/src/icon.ml index 4ed4972..d59a69f 100644 --- a/src/icon.ml +++ b/src/icon.ml @@ -46,12 +46,12 @@ let opt_to_jv = function match o with Some s -> Jv.of_string s | None -> Jv.of_bool false ) let create icon_url options = - let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in - let l = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in + let l = Array.map (fun o -> (to_string o, opt_to_jv o)) options in + let l = Array.append [| ("iconUrl", Jv.of_string icon_url) |] l in Jv.call Global.leaflet "icon" [| Jv.obj l |] let create_div ~html ~bg_pos options = - let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in + let l = Array.map (fun o -> (to_string o, opt_to_jv o)) options in let div_options = let html = match html with @@ -63,9 +63,9 @@ let create_div ~html ~bg_pos options = | None -> [] | Some bg_pos -> [ ("bgPos", Point.to_jv bg_pos) ] in - html @ bg_pos + html @ bg_pos |> Array.of_list in - let l = Array.of_list @@ div_options @ l in + let l = Array.append div_options l in Jv.call Global.leaflet "divIcon" [| Jv.obj l |] let set_default_image_path s = diff --git a/src/icon.mli b/src/icon.mli index 451b51f..f490910 100644 --- a/src/icon.mli +++ b/src/icon.mli @@ -24,13 +24,13 @@ type opt = (** [create icon_url options] Creates an icon instance with the given [options], and the required `iconUrl` option set to [icon_url] *) -val create : string -> opt list -> t +val create : string -> opt array -> t (** [create_div ~html ~bg_pos options] Creates an DivIcon instance with the given [options], [bg_pos] is the optional relative position of the background, in pixels [html] is custom HTML code to put inside the div element, empty by default. *) -val create_div : html:string option -> bg_pos:Point.t option -> opt list -> t +val create_div : html:string option -> bg_pos:Point.t option -> opt array -> t (** Sets the path of the default icon *) val set_default_image_path : string -> unit diff --git a/src/layer.ml b/src/layer.ml index 12c35c3..e001331 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -110,13 +110,10 @@ let geojson_opt_to_jv = function | Filter f -> Jv.repr f | Coords_to_latlng f -> Jv.repr f -let create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t = +let create_geojson : Jv.t -> geojson_opt array -> [ `Geojson ] t = fun geojson options -> let l = - Array.of_list - @@ List.map - (fun o -> (geojson_opt_to_string o, geojson_opt_to_jv o)) - options + Array.map (fun o -> (geojson_opt_to_string o, geojson_opt_to_jv o)) options in let jv_t = Jv.call Global.leaflet "geoJSON" [| geojson; Jv.obj l |] in Geojson jv_t @@ -205,21 +202,21 @@ let tile_layer_opt_to_jv = function Jv.call Global.leaflet "latLngBounds" [| Latlng.to_jv a; Latlng.to_jv b |] let create_tile : - string -> attribution:string -> tile_layer_opt list -> [ `Tile ] t = + string -> attribution:string -> tile_layer_opt array -> [ `Tile ] t = fun url ~attribution options -> let arr = - Array.of_list - @@ ("attribution", Jv.of_string attribution) - :: List.map - (fun o -> (tile_layer_opt_to_string o, tile_layer_opt_to_jv o)) - options + Array.append + [| ("attribution", Jv.of_string attribution) |] + (Array.map + (fun o -> (tile_layer_opt_to_string o, tile_layer_opt_to_jv o)) + options ) in let jv_t = Jv.call Global.leaflet "tileLayer" [| Jv.of_string url; Jv.obj arr |] in Tile jv_t -let create_tile_osm : tile_layer_opt list -> [ `Tile ] t = +let create_tile_osm : tile_layer_opt array -> [ `Tile ] t = fun options -> let url = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" in let attribution = @@ -231,8 +228,8 @@ let create_tile_osm : tile_layer_opt list -> [ `Tile ] t = (* Vector Layers *) -let create_polyline : Latlng.t list -> [ `Vector ] t = +let create_polyline : Latlng.t array -> [ `Vector ] t = fun l -> - let l = Jv.of_list Latlng.to_jv l in + let l = Jv.of_array Latlng.to_jv l in let jv_t = Jv.call Global.leaflet "polyline" [| l |] in Vector jv_t diff --git a/src/layer.mli b/src/layer.mli index 1f34363..170ceb9 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -62,7 +62,7 @@ type geojson_opt = | Markers_inherit_options of bool (** [create_geojson geojson] is a new geojson layer *) -val create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t +val create_geojson : Jv.t -> geojson_opt array -> [ `Geojson ] t (** Tile layers *) @@ -93,12 +93,12 @@ type tile_layer_opt = (** [create_tile url attribution opts] create a new tile layer *) val create_tile : - string -> attribution:string -> tile_layer_opt list -> [ `Tile ] t + string -> attribution:string -> tile_layer_opt array -> [ `Tile ] t (** [create_tile_osm opts] create a new tile layer with tile server and attribution set to [openstreetmap.org]. See {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) -val create_tile_osm : tile_layer_opt list -> [ `Tile ] t +val create_tile_osm : tile_layer_opt array -> [ `Tile ] t (** [create_polyline l] create a polyline layer from [l] *) -val create_polyline : Latlng.t list -> [ `Vector ] t +val create_polyline : Latlng.t array -> [ `Vector ] t diff --git a/src/marker.ml b/src/marker.ml index 93ebd05..7bf5f14 100644 --- a/src/marker.ml +++ b/src/marker.ml @@ -40,11 +40,9 @@ let opt_to_jv = function | Z_index_offset i | Rise_offset i -> Jv.of_int i | Opacity f -> Jv.of_float f -let create : Latlng.t -> opt list -> t = +let create : Latlng.t -> opt array -> t = fun latlng options -> - let l = - Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options - in + let l = Array.map (fun o -> (opt_to_string o, opt_to_jv o)) options in let jv_t = Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng; Jv.obj l |] in diff --git a/src/marker.mli b/src/marker.mli index ebb8096..a8c1237 100644 --- a/src/marker.mli +++ b/src/marker.mli @@ -17,7 +17,7 @@ type opt = (** [create latlng options] is a new marker with the same position as [latlng] and with options set to [options] *) -val create : Latlng.t -> opt list -> t +val create : Latlng.t -> opt array -> t (** Returns the current geographical position of the marker. *) val get_latlng : t -> Latlng.t diff --git a/src/popup.ml b/src/popup.ml index 3960a81..d3c077a 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -69,9 +69,7 @@ let opt_to_jv = function | Pane s | Class_name s -> Jv.of_string s let create ~content ~latlng options = - let l = - Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options - in + let l = Array.map (fun o -> (opt_to_string o, opt_to_jv o)) options in let popup = Jv.call Global.leaflet "popup" [| Jv.obj l |] in let popup = match latlng with @@ -87,9 +85,7 @@ let create ~content ~latlng options = popup let create_from_el el ~latlng options = - let l = - Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options - in + let l = Array.map (fun o -> (opt_to_string o, opt_to_jv o)) options in let popup = Jv.call Global.leaflet "popup" [| Jv.obj l |] in let popup = match latlng with diff --git a/src/popup.mli b/src/popup.mli index d099745..f8dfc84 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -43,8 +43,8 @@ val opt_to_jv : opt -> Jv.t (** [create ~content ~latlng options] is a new popup setup with [options], position set to [latlng] and content to [s] *) -val create : content:string option -> latlng:Latlng.t option -> opt list -> t +val create : content:string option -> latlng:Latlng.t option -> opt array -> t (** [create_from_el el latlng options] is a new popup setup with [options], position set to [latlng] and content to [el] *) -val create_from_el : Brr.El.t -> latlng:Latlng.t option -> opt list -> t +val create_from_el : Brr.El.t -> latlng:Latlng.t option -> opt array -> t From 0ee6adaad5d5b41a1bc64f1ca815ec3c9d12b2ce Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 30 Jan 2024 18:45:24 +0100 Subject: [PATCH 32/43] add cirecle marker --- src/layer.ml | 9 +++++++++ src/layer.mli | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/src/layer.ml b/src/layer.ml index e001331..8475a90 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -228,8 +228,17 @@ let create_tile_osm : tile_layer_opt array -> [ `Tile ] t = (* Vector Layers *) +(* TODO add options *) + let create_polyline : Latlng.t array -> [ `Vector ] t = fun l -> let l = Jv.of_array Latlng.to_jv l in let jv_t = Jv.call Global.leaflet "polyline" [| l |] in Vector jv_t + +let create_circle_marker : Latlng.t -> float -> [ `Vector ] t = + fun center radius -> + let center = Latlng.to_jv center in + let arr = [| ("radius", Jv.of_float radius) |] in + let jv_t = Jv.call Global.leaflet "circleMarker" [| center; Jv.obj arr |] in + Vector jv_t diff --git a/src/layer.mli b/src/layer.mli index 170ceb9..b2da3ae 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -102,3 +102,7 @@ val create_tile_osm : tile_layer_opt array -> [ `Tile ] t (** [create_polyline l] create a polyline layer from [l] *) val create_polyline : Latlng.t array -> [ `Vector ] t + +(** [create_circle_marker c r] create a cirecle marker layer with center [c] and + radius [r] *) +val create_circle_marker : Latlng.t -> float -> [ `Vector ] t From df486e8a6579d39e2c9552094beb00023391b579 Mon Sep 17 00:00:00 2001 From: Swrup Date: Wed, 3 Jul 2024 11:19:26 +0200 Subject: [PATCH 33/43] close_popup: rm label --- src/map.ml | 2 +- src/map.mli | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/map.ml b/src/map.ml index 9dec8d6..3c3ae0e 100644 --- a/src/map.ml +++ b/src/map.ml @@ -50,7 +50,7 @@ let wrap_latlng latlng map = let open_popup popup map = ignore @@ Jv.call map "openPopup" [| Popup.to_jv popup |] -let close_popup ~popup map = +let close_popup popup map = ignore @@ match popup with diff --git a/src/map.mli b/src/map.mli index ede2965..b50e841 100644 --- a/src/map.mli +++ b/src/map.mli @@ -52,4 +52,4 @@ val to_jv : t -> Jv.t val open_popup : Popup.t -> t -> unit (* [close_popup opt map] if [opt] is [Some popup] closes [popup] else closes previously opened popup *) -val close_popup : popup:Popup.t option -> t -> unit +val close_popup : Popup.t option -> t -> unit From 8b7e5851687a7ec60237f31570ec0ed451182c25 Mon Sep 17 00:00:00 2001 From: Swrup Date: Wed, 3 Jul 2024 11:19:48 +0200 Subject: [PATCH 34/43] ocamlformat --- .ocamlformat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ocamlformat b/.ocamlformat index 74ae9c5..f948087 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version=0.26.1 +version=0.26.2 assignment-operator=end-line break-cases=fit break-fun-decl=wrap From 05d561dac636e5334dfdc7d91d1485db70e0f72c Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 18 Jul 2024 10:36:27 +0200 Subject: [PATCH 35/43] create_geojson need a json object --- src/layer.ml | 2 +- src/layer.mli | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index 8475a90..69b0f7d 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -110,7 +110,7 @@ let geojson_opt_to_jv = function | Filter f -> Jv.repr f | Coords_to_latlng f -> Jv.repr f -let create_geojson : Jv.t -> geojson_opt array -> [ `Geojson ] t = +let create_geojson : Brr.Json.t -> geojson_opt array -> [ `Geojson ] t = fun geojson options -> let l = Array.map (fun o -> (geojson_opt_to_string o, geojson_opt_to_jv o)) options diff --git a/src/layer.mli b/src/layer.mli index b2da3ae..e01be64 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -62,7 +62,7 @@ type geojson_opt = | Markers_inherit_options of bool (** [create_geojson geojson] is a new geojson layer *) -val create_geojson : Jv.t -> geojson_opt array -> [ `Geojson ] t +val create_geojson : Brr.Json.t -> geojson_opt array -> [ `Geojson ] t (** Tile layers *) From 2b8f3e8e7cc25e326004c108fe360eae4db6e98f Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 8 Feb 2024 15:37:38 +0100 Subject: [PATCH 36/43] update leaflet.js --- src/leaflet.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/leaflet.js b/src/leaflet.js index 21f499c..a3bf693 100644 --- a/src/leaflet.js +++ b/src/leaflet.js @@ -1,6 +1,6 @@ /* @preserve - * Leaflet 1.7.1, a JS library for interactive maps. http://leafletjs.com - * (c) 2010-2019 Vladimir Agafonkin, (c) 2010-2011 CloudMade + * Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com + * (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade */ -!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i(t.L={})}(this,function(t){"use strict";function h(t){for(var i,e,n=1,o=arguments.length;n=this.min.x&&e.x<=this.max.x&&i.y>=this.min.y&&e.y<=this.max.y},intersects:function(t){t=O(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>=i.x&&n.x<=e.x,r=o.y>=i.y&&n.y<=e.y;return s&&r},overlaps:function(t){t=O(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>i.x&&n.xi.y&&n.y=n.lat&&e.lat<=o.lat&&i.lng>=n.lng&&e.lng<=o.lng},intersects:function(t){t=N(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>=i.lat&&n.lat<=e.lat,r=o.lng>=i.lng&&n.lng<=e.lng;return s&&r},overlaps:function(t){t=N(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>i.lat&&n.lati.lng&&n.lng';var i=t.firstChild;return i.style.behavior="url(#default#VML)",i&&"object"==typeof i.adj}catch(t){return!1}}();function kt(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var Bt={ie:tt,ielt9:it,edge:et,webkit:nt,android:ot,android23:st,androidStock:at,opera:ht,chrome:ut,gecko:lt,safari:ct,phantom:_t,opera12:dt,win:pt,ie3d:mt,webkit3d:ft,gecko3d:gt,any3d:vt,mobile:yt,mobileWebkit:xt,mobileWebkit3d:wt,msPointer:Pt,pointer:Lt,touch:bt,mobileOpera:Tt,mobileGecko:Mt,retina:zt,passiveEvents:Ct,canvas:St,svg:Zt,vml:Et},At=Pt?"MSPointerDown":"pointerdown",It=Pt?"MSPointerMove":"pointermove",Ot=Pt?"MSPointerUp":"pointerup",Rt=Pt?"MSPointerCancel":"pointercancel",Nt={},Dt=!1;function jt(t,i,e,n){function o(t){Ut(t,r)}var s,r,a,h,u,l,c,_;function d(t){t.pointerType===(t.MSPOINTER_TYPE_MOUSE||"mouse")&&0===t.buttons||Ut(t,h)}return"touchstart"===i?(u=t,l=e,c=n,_=p(function(t){t.MSPOINTER_TYPE_TOUCH&&t.pointerType===t.MSPOINTER_TYPE_TOUCH&&Ri(t),Ut(t,l)}),u["_leaflet_touchstart"+c]=_,u.addEventListener(At,_,!1),Dt||(document.addEventListener(At,Wt,!0),document.addEventListener(It,Ht,!0),document.addEventListener(Ot,Ft,!0),document.addEventListener(Rt,Ft,!0),Dt=!0)):"touchmove"===i?(h=e,(a=t)["_leaflet_touchmove"+n]=d,a.addEventListener(It,d,!1)):"touchend"===i&&(r=e,(s=t)["_leaflet_touchend"+n]=o,s.addEventListener(Ot,o,!1),s.addEventListener(Rt,o,!1)),this}function Wt(t){Nt[t.pointerId]=t}function Ht(t){Nt[t.pointerId]&&(Nt[t.pointerId]=t)}function Ft(t){delete Nt[t.pointerId]}function Ut(t,i){for(var e in t.touches=[],Nt)t.touches.push(Nt[e]);t.changedTouches=[t],i(t)}var Vt=Pt?"MSPointerDown":Lt?"pointerdown":"touchstart",qt=Pt?"MSPointerUp":Lt?"pointerup":"touchend",Gt="_leaflet_";var Kt,Yt,Xt,Jt,$t,Qt,ti=fi(["transform","webkitTransform","OTransform","MozTransform","msTransform"]),ii=fi(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),ei="webkitTransition"===ii||"OTransition"===ii?ii+"End":"transitionend";function ni(t){return"string"==typeof t?document.getElementById(t):t}function oi(t,i){var e,n=t.style[i]||t.currentStyle&&t.currentStyle[i];return n&&"auto"!==n||!document.defaultView||(n=(e=document.defaultView.getComputedStyle(t,null))?e[i]:null),"auto"===n?null:n}function si(t,i,e){var n=document.createElement(t);return n.className=i||"",e&&e.appendChild(n),n}function ri(t){var i=t.parentNode;i&&i.removeChild(t)}function ai(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function hi(t){var i=t.parentNode;i&&i.lastChild!==t&&i.appendChild(t)}function ui(t){var i=t.parentNode;i&&i.firstChild!==t&&i.insertBefore(t,i.firstChild)}function li(t,i){if(void 0!==t.classList)return t.classList.contains(i);var e=pi(t);return 0this.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,i){this._enforcingBounds=!0;var e=this.getCenter(),n=this._limitCenter(e,this._zoom,N(t));return e.equals(n)||this.panTo(n,i),this._enforcingBounds=!1,this},panInside:function(t,i){var e,n,o=A((i=i||{}).paddingTopLeft||i.padding||[0,0]),s=A(i.paddingBottomRight||i.padding||[0,0]),r=this.getCenter(),a=this.project(r),h=this.project(t),u=this.getPixelBounds(),l=u.getSize().divideBy(2),c=O([u.min.add(o),u.max.subtract(s)]);return c.contains(h)||(this._enforcingBounds=!0,e=a.subtract(h),n=A(h.x+e.x,h.y+e.y),(h.xc.max.x)&&(n.x=a.x-e.x,0c.max.y)&&(n.y=a.y-e.y,0=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,i){for(var e,n=[],o="mouseout"===i||"mouseover"===i,s=t.target||t.srcElement,r=!1;s;){if((e=this._targets[m(s)])&&("click"===i||"preclick"===i)&&!t._simulated&&this._draggableMoved(e)){r=!0;break}if(e&&e.listens(i,!0)){if(o&&!Vi(s,t))break;if(n.push(e),o)break}if(s===this._container)break;s=s.parentNode}return n.length||r||o||!Vi(s,t)||(n=[this]),n},_handleDOMEvent:function(t){var i;this._loaded&&!Ui(t)&&("mousedown"!==(i=t.type)&&"keypress"!==i&&"keyup"!==i&&"keydown"!==i||Pi(t.target||t.srcElement),this._fireDOMEvent(t,i))},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,i,e){var n;if("click"===t.type&&((n=h({},t)).type="preclick",this._fireDOMEvent(n,n.type,e)),!t._stopped&&(e=(e||[]).concat(this._findEventTargets(t,i))).length){var o=e[0];"contextmenu"===i&&o.listens(i,!0)&&Ri(t);var s,r={originalEvent:t};"keypress"!==t.type&&"keydown"!==t.type&&"keyup"!==t.type&&(s=o.getLatLng&&(!o._radius||o._radius<=10),r.containerPoint=s?this.latLngToContainerPoint(o.getLatLng()):this.mouseEventToContainerPoint(t),r.layerPoint=this.containerPointToLayerPoint(r.containerPoint),r.latlng=s?o.getLatLng():this.layerPointToLatLng(r.layerPoint));for(var a=0;athis.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(i),o=this._getCenterOffset(t)._divideBy(1-1/n);return!(!0!==e.animate&&!this.getSize().contains(o))&&(M(function(){this._moveStart(!0,!1)._animateZoom(t,i,!0)},this),!0)},_animateZoom:function(t,i,e,n){this._mapPane&&(e&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=i,ci(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:i,noUpdate:n}),setTimeout(p(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&_i(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),M(function(){this._moveEnd(!0)},this))}});function Yi(t){return new Xi(t)}var Xi=S.extend({options:{position:"topright"},initialize:function(t){c(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var i=this._map;return i&&i.removeControl(this),this.options.position=t,i&&i.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var i=this._container=this.onAdd(t),e=this.getPosition(),n=t._controlCorners[e];return ci(i,"leaflet-control"),-1!==e.indexOf("bottom")?n.insertBefore(i,n.firstChild):n.appendChild(i),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(ri(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0",n=document.createElement("div");return n.innerHTML=e,n.firstChild},_addItem:function(t){var i,e=document.createElement("label"),n=this._map.hasLayer(t.layer);t.overlay?((i=document.createElement("input")).type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=n):i=this._createRadioElement("leaflet-base-layers_"+m(this),n),this._layerControlInputs.push(i),i.layerId=m(t.layer),zi(i,"click",this._onInputClick,this);var o=document.createElement("span");o.innerHTML=" "+t.name;var s=document.createElement("div");return e.appendChild(s),s.appendChild(i),s.appendChild(o),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(e),this._checkDisabledLayers(),e},_onInputClick:function(){var t,i,e=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=e.length-1;0<=s;s--)t=e[s],i=this._getLayer(t.layerId).layer,t.checked?n.push(i):t.checked||o.push(i);for(s=0;si.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),$i=Xi.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"−",zoomOutTitle:"Zoom out"},onAdd:function(t){var i="leaflet-control-zoom",e=si("div",i+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,i+"-in",e,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,i+"-out",e,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),e},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,i,e,n,o){var s=si("a",e,n);return s.innerHTML=t,s.href="#",s.title=i,s.setAttribute("role","button"),s.setAttribute("aria-label",i),Oi(s),zi(s,"click",Ni),zi(s,"click",o,this),zi(s,"click",this._refocusOnMap,this),s},_updateDisabled:function(){var t=this._map,i="leaflet-disabled";_i(this._zoomInButton,i),_i(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMinZoom()||ci(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMaxZoom()||ci(this._zoomInButton,i)}});Ki.mergeOptions({zoomControl:!0}),Ki.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new $i,this.addControl(this.zoomControl))});var Qi=Xi.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var i="leaflet-control-scale",e=si("div",i),n=this.options;return this._addScales(n,i+"-line",e),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),e},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,i,e){t.metric&&(this._mScale=si("div",i,e)),t.imperial&&(this._iScale=si("div",i,e))},_update:function(){var t=this._map,i=t.getSize().y/2,e=t.distance(t.containerPointToLatLng([0,i]),t.containerPointToLatLng([this.options.maxWidth,i]));this._updateScales(e)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var i=this._getRoundNum(t),e=i<1e3?i+" m":i/1e3+" km";this._updateScale(this._mScale,e,i/t)},_updateImperial:function(t){var i,e,n,o=3.2808399*t;5280Leaflet'},initialize:function(t){c(this,t),this._attributions={}},onAdd:function(t){for(var i in(t.attributionControl=this)._container=si("div","leaflet-control-attribution"),Oi(this._container),t._layers)t._layers[i].getAttribution&&this.addAttribution(t._layers[i].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t=[];for(var i in this._attributions)this._attributions[i]&&t.push(i);var e=[];this.options.prefix&&e.push(this.options.prefix),t.length&&e.push(t.join(", ")),this._container.innerHTML=e.join(" | ")}}});Ki.mergeOptions({attributionControl:!0}),Ki.addInitHook(function(){this.options.attributionControl&&(new te).addTo(this)});Xi.Layers=Ji,Xi.Zoom=$i,Xi.Scale=Qi,Xi.Attribution=te,Yi.layers=function(t,i,e){return new Ji(t,i,e)},Yi.zoom=function(t){return new $i(t)},Yi.scale=function(t){return new Qi(t)},Yi.attribution=function(t){return new te(t)};var ie=S.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}});ie.addTo=function(t,i){return t.addHandler(i,this),this};var ee,ne={Events:Z},oe=bt?"touchstart mousedown":"mousedown",se={mousedown:"mouseup",touchstart:"touchend",pointerdown:"touchend",MSPointerDown:"touchend"},re={mousedown:"mousemove",touchstart:"touchmove",pointerdown:"touchmove",MSPointerDown:"touchmove"},ae=E.extend({options:{clickTolerance:3},initialize:function(t,i,e,n){c(this,n),this._element=t,this._dragStartTarget=i||t,this._preventOutline=e},enable:function(){this._enabled||(zi(this._dragStartTarget,oe,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(ae._dragging===this&&this.finishDrag(),Si(this._dragStartTarget,oe,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){var i,e;!t._simulated&&this._enabled&&(this._moved=!1,li(this._element,"leaflet-zoom-anim")||ae._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((ae._dragging=this)._preventOutline&&Pi(this._element),xi(),Xt(),this._moving||(this.fire("down"),i=t.touches?t.touches[0]:t,e=bi(this._element),this._startPoint=new k(i.clientX,i.clientY),this._parentScale=Ti(e),zi(document,re[t.type],this._onMove,this),zi(document,se[t.type],this._onUp,this))))},_onMove:function(t){var i,e;!t._simulated&&this._enabled&&(t.touches&&1i&&(e.push(t[n]),o=n);oi.max.x&&(e|=2),t.yi.max.y&&(e|=8),e}function de(t,i,e,n){var o,s=i.x,r=i.y,a=e.x-s,h=e.y-r,u=a*a+h*h;return 0this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()t.y!=n.y>t.y&&t.x<(n.x-e.x)*(t.y-e.y)/(n.y-e.y)+e.x&&(u=!u);return u||Oe.prototype._containsPoint.call(this,t,!0)}});var Ne=Ce.extend({initialize:function(t,i){c(this,i),this._layers={},t&&this.addData(t)},addData:function(t){var i,e,n,o=g(t)?t:t.features;if(o){for(i=0,e=o.length;iu.x&&(l=s.x+n-u.x+h.x),s.x-l-a.x<0&&(l=s.x-a.x),s.y+e+h.y>u.y&&(c=s.y+e-u.y+h.y),s.y-c-a.y<0&&(c=s.y-a.y),(l||c)&&t.fire("autopanstart").panBy([l,c]))},_onCloseButtonClick:function(t){this._close(),Ni(t)},_getAnchor:function(){return A(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}});Ki.mergeOptions({closePopupOnClick:!0}),Ki.include({openPopup:function(t,i,e){return t instanceof tn||(t=new tn(e).setContent(t)),i&&t.setLatLng(i),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),Me.include({bindPopup:function(t,i){return t instanceof tn?(c(t,i),(this._popup=t)._source=this):(this._popup&&!i||(this._popup=new tn(i,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,i){return this._popup&&this._map&&(i=this._popup._prepareOpen(this,t,i),this._map.openPopup(this._popup,i)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var i=t.layer||t.target;this._popup&&this._map&&(Ni(t),i instanceof Be?this.openPopup(t.layer||t.target,t.latlng):this._map.hasLayer(this._popup)&&this._popup._source===i?this.closePopup():this.openPopup(i,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}});var en=Qe.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){Qe.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&this._source.fire("tooltipopen",{tooltip:this},!0)},onRemove:function(t){Qe.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&this._source.fire("tooltipclose",{tooltip:this},!0)},getEvents:function(){var t=Qe.prototype.getEvents.call(this);return bt&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=si("div",t)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var i,e=this._map,n=this._container,o=e.latLngToContainerPoint(e.getCenter()),s=e.layerPointToContainerPoint(t),r=this.options.direction,a=n.offsetWidth,h=n.offsetHeight,u=A(this.options.offset),l=this._getAnchor(),c="top"===r?(i=a/2,h):"bottom"===r?(i=a/2,0):(i="center"===r?a/2:"right"===r?0:"left"===r?a:s.xthis.options.maxZoom||nthis.options.maxZoom||void 0!==this.options.minZoom&&oe.max.x)||!i.wrapLat&&(t.ye.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return N(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var i=this._map,e=this.getTileSize(),n=t.scaleBy(e),o=n.add(e);return[i.unproject(n,t.z),i.unproject(o,t.z)]},_tileCoordsToBounds:function(t){var i=this._tileCoordsToNwSe(t),e=new R(i[0],i[1]);return this.options.noWrap||(e=this._map.wrapLatLngBounds(e)),e},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var i=t.split(":"),e=new k(+i[0],+i[1]);return e.z=+i[2],e},_removeTile:function(t){var i=this._tiles[t];i&&(ri(i.el),delete this._tiles[t],this.fire("tileunload",{tile:i.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){ci(t,"leaflet-tile");var i=this.getTileSize();t.style.width=i.x+"px",t.style.height=i.y+"px",t.onselectstart=a,t.onmousemove=a,it&&this.options.opacity<1&&mi(t,this.options.opacity),ot&&!st&&(t.style.WebkitBackfaceVisibility="hidden")},_addTile:function(t,i){var e=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),p(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&M(p(this._tileReady,this,t,null,o)),vi(o,e),this._tiles[n]={el:o,coords:t,current:!0},i.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,i,e){i&&this.fire("tileerror",{error:i,tile:e,coords:t});var n=this._tileCoordsToKey(t);(e=this._tiles[n])&&(e.loaded=+new Date,this._map._fadeAnimated?(mi(e.el,0),z(this._fadeFrame),this._fadeFrame=M(this._updateOpacity,this)):(e.active=!0,this._pruneTiles()),i||(ci(e.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:e.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),it||!this._map._fadeAnimated?M(this._pruneTiles,this):setTimeout(p(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var i=new k(this._wrapX?o(t.x,this._wrapX):t.x,this._wrapY?o(t.y,this._wrapY):t.y);return i.z=t.z,i},_pxBoundsToTileRange:function(t){var i=this.getTileSize();return new I(t.min.unscaleBy(i).floor(),t.max.unscaleBy(i).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var sn=on.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,i){this._url=t,(i=c(this,i)).detectRetina&&zt&&0')}}catch(t){return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),_n={_initContainer:function(){this._container=si("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(hn.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var i=t._container=cn("shape");ci(i,"leaflet-vml-shape "+(this.options.className||"")),i.coordsize="1 1",t._path=cn("path"),i.appendChild(t._path),this._updateStyle(t),this._layers[m(t)]=t},_addPath:function(t){var i=t._container;this._container.appendChild(i),t.options.interactive&&t.addInteractiveTarget(i)},_removePath:function(t){var i=t._container;ri(i),t.removeInteractiveTarget(i),delete this._layers[m(t)]},_updateStyle:function(t){var i=t._stroke,e=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(i=i||(t._stroke=cn("stroke")),o.appendChild(i),i.weight=n.weight+"px",i.color=n.color,i.opacity=n.opacity,n.dashArray?i.dashStyle=g(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):i.dashStyle="",i.endcap=n.lineCap.replace("butt","flat"),i.joinstyle=n.lineJoin):i&&(o.removeChild(i),t._stroke=null),n.fill?(e=e||(t._fill=cn("fill")),o.appendChild(e),e.color=n.fillColor||n.color,e.opacity=n.fillOpacity):e&&(o.removeChild(e),t._fill=null)},_updateCircle:function(t){var i=t._point.round(),e=Math.round(t._radius),n=Math.round(t._radiusY||e);this._setPath(t,t._empty()?"M0 0":"AL "+i.x+","+i.y+" "+e+","+n+" 0,23592600")},_setPath:function(t,i){t._path.v=i},_bringToFront:function(t){hi(t._container)},_bringToBack:function(t){ui(t._container)}},dn=Et?cn:J,pn=hn.extend({getEvents:function(){var t=hn.prototype.getEvents.call(this);return t.zoomstart=this._onZoomStart,t},_initContainer:function(){this._container=dn("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=dn("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){ri(this._container),Si(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_onZoomStart:function(){this._update()},_update:function(){var t,i,e;this._map._animatingZoom&&this._bounds||(hn.prototype._update.call(this),i=(t=this._bounds).getSize(),e=this._container,this._svgSize&&this._svgSize.equals(i)||(this._svgSize=i,e.setAttribute("width",i.x),e.setAttribute("height",i.y)),vi(e,t.min),e.setAttribute("viewBox",[t.min.x,t.min.y,i.x,i.y].join(" ")),this.fire("update"))},_initPath:function(t){var i=t._path=dn("path");t.options.className&&ci(i,t.options.className),t.options.interactive&&ci(i,"leaflet-interactive"),this._updateStyle(t),this._layers[m(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){ri(t._path),t.removeInteractiveTarget(t._path),delete this._layers[m(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var i=t._path,e=t.options;i&&(e.stroke?(i.setAttribute("stroke",e.color),i.setAttribute("stroke-opacity",e.opacity),i.setAttribute("stroke-width",e.weight),i.setAttribute("stroke-linecap",e.lineCap),i.setAttribute("stroke-linejoin",e.lineJoin),e.dashArray?i.setAttribute("stroke-dasharray",e.dashArray):i.removeAttribute("stroke-dasharray"),e.dashOffset?i.setAttribute("stroke-dashoffset",e.dashOffset):i.removeAttribute("stroke-dashoffset")):i.setAttribute("stroke","none"),e.fill?(i.setAttribute("fill",e.fillColor||e.color),i.setAttribute("fill-opacity",e.fillOpacity),i.setAttribute("fill-rule",e.fillRule||"evenodd")):i.setAttribute("fill","none"))},_updatePoly:function(t,i){this._setPath(t,$(t._parts,i))},_updateCircle:function(t){var i=t._point,e=Math.max(Math.round(t._radius),1),n="a"+e+","+(Math.max(Math.round(t._radiusY),1)||e)+" 0 1,0 ",o=t._empty()?"M0 0":"M"+(i.x-e)+","+i.y+n+2*e+",0 "+n+2*-e+",0 ";this._setPath(t,o)},_setPath:function(t,i){t._path.setAttribute("d",i)},_bringToFront:function(t){hi(t._path)},_bringToBack:function(t){ui(t._path)}});function mn(t){return Zt||Et?new pn(t):null}Et&&pn.include(_n),Ki.include({getRenderer:function(t){var i=(i=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer)||(this._renderer=this._createRenderer());return this.hasLayer(i)||this.addLayer(i),i},_getPaneRenderer:function(t){if("overlayPane"===t||void 0===t)return!1;var i=this._paneRenderers[t];return void 0===i&&(i=this._createRenderer({pane:t}),this._paneRenderers[t]=i),i},_createRenderer:function(t){return this.options.preferCanvas&&ln(t)||mn(t)}});var fn=Re.extend({initialize:function(t,i){Re.prototype.initialize.call(this,this._boundsToLatLngs(t),i)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=N(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});pn.create=dn,pn.pointsToPath=$,Ne.geometryToLayer=De,Ne.coordsToLatLng=We,Ne.coordsToLatLngs=He,Ne.latLngToCoords=Fe,Ne.latLngsToCoords=Ue,Ne.getFeature=Ve,Ne.asFeature=qe,Ki.mergeOptions({boxZoom:!0});var gn=ie.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){zi(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){Si(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){ri(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),Xt(),xi(),this._startPoint=this._map.mouseEventToContainerPoint(t),zi(document,{contextmenu:Ni,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=si("div","leaflet-zoom-box",this._container),ci(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var i=new I(this._point,this._startPoint),e=i.getSize();vi(this._box,i.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(ri(this._box),_i(this._container,"leaflet-crosshair")),Jt(),wi(),Si(document,{contextmenu:Ni,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){var i;1!==t.which&&1!==t.button||(this._finish(),this._moved&&(this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(p(this._resetState,this),0),i=new R(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point)),this._map.fitBounds(i).fire("boxzoomend",{boxZoomBounds:i})))},_onKeyDown:function(t){27===t.keyCode&&this._finish()}});Ki.addInitHook("addHandler","boxZoom",gn),Ki.mergeOptions({doubleClickZoom:!0});var vn=ie.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var i=this._map,e=i.getZoom(),n=i.options.zoomDelta,o=t.originalEvent.shiftKey?e-n:e+n;"center"===i.options.doubleClickZoom?i.setZoom(o):i.setZoomAround(t.containerPoint,o)}});Ki.addInitHook("addHandler","doubleClickZoom",vn),Ki.mergeOptions({dragging:!0,inertia:!st,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0});var yn=ie.extend({addHooks:function(){var t;this._draggable||(t=this._map,this._draggable=new ae(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))),ci(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){_i(this._map._container,"leaflet-grab"),_i(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t,i=this._map;i._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity?(t=N(this._map.options.maxBounds),this._offsetLimit=O(this._map.latLngToContainerPoint(t.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(t.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))):this._offsetLimit=null,i.fire("movestart").fire("dragstart"),i.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){var i,e;this._map.options.inertia&&(i=this._lastTime=+new Date,e=this._lastPos=this._draggable._absPos||this._draggable._newPos,this._positions.push(e),this._times.push(i),this._prunePositions(i)),this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1i.max.x&&(t.x=this._viscousLimit(t.x,i.max.x)),t.y>i.max.y&&(t.y=this._viscousLimit(t.y,i.max.y)),this._draggable._newPos=this._draggable._startPos.add(t))},_onPreDragWrap:function(){var t=this._worldWidth,i=Math.round(t/2),e=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-i+e)%t+i-e,s=(n+i+e)%t-i-e,r=Math.abs(o+e)i.getMaxZoom()&&1=this.min.x&&i.x<=this.max.x&&e.y>=this.min.y&&i.y<=this.max.y},intersects:function(t){t=_(t);var e=this.min,i=this.max,n=t.min,t=t.max,o=t.x>=e.x&&n.x<=i.x,t=t.y>=e.y&&n.y<=i.y;return o&&t},overlaps:function(t){t=_(t);var e=this.min,i=this.max,n=t.min,t=t.max,o=t.x>e.x&&n.xe.y&&n.y=n.lat&&i.lat<=o.lat&&e.lng>=n.lng&&i.lng<=o.lng},intersects:function(t){t=g(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),t=t.getNorthEast(),o=t.lat>=e.lat&&n.lat<=i.lat,t=t.lng>=e.lng&&n.lng<=i.lng;return o&&t},overlaps:function(t){t=g(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),t=t.getNorthEast(),o=t.lat>e.lat&&n.late.lng&&n.lng","http://www.w3.org/2000/svg"===(Wt.firstChild&&Wt.firstChild.namespaceURI));function y(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var b={ie:pt,ielt9:mt,edge:n,webkit:ft,android:gt,android23:vt,androidStock:yt,opera:xt,chrome:wt,gecko:bt,safari:Pt,phantom:Lt,opera12:o,win:Tt,ie3d:Mt,webkit3d:zt,gecko3d:_t,any3d:Ct,mobile:Zt,mobileWebkit:St,mobileWebkit3d:Et,msPointer:kt,pointer:Ot,touch:Bt,touchNative:At,mobileOpera:It,mobileGecko:Rt,retina:Nt,passiveEvents:Dt,canvas:jt,svg:Ht,vml:!Ht&&function(){try{var t=document.createElement("div"),e=(t.innerHTML='',t.firstChild);return e.style.behavior="url(#default#VML)",e&&"object"==typeof e.adj}catch(t){return!1}}(),inlineSvg:Wt,mac:0===navigator.platform.indexOf("Mac"),linux:0===navigator.platform.indexOf("Linux")},Ft=b.msPointer?"MSPointerDown":"pointerdown",Ut=b.msPointer?"MSPointerMove":"pointermove",Vt=b.msPointer?"MSPointerUp":"pointerup",qt=b.msPointer?"MSPointerCancel":"pointercancel",Gt={touchstart:Ft,touchmove:Ut,touchend:Vt,touchcancel:qt},Kt={touchstart:function(t,e){e.MSPOINTER_TYPE_TOUCH&&e.pointerType===e.MSPOINTER_TYPE_TOUCH&&O(e);ee(t,e)},touchmove:ee,touchend:ee,touchcancel:ee},Yt={},Xt=!1;function Jt(t,e,i){return"touchstart"!==e||Xt||(document.addEventListener(Ft,$t,!0),document.addEventListener(Ut,Qt,!0),document.addEventListener(Vt,te,!0),document.addEventListener(qt,te,!0),Xt=!0),Kt[e]?(i=Kt[e].bind(this,i),t.addEventListener(Gt[e],i,!1),i):(console.warn("wrong event specified:",e),u)}function $t(t){Yt[t.pointerId]=t}function Qt(t){Yt[t.pointerId]&&(Yt[t.pointerId]=t)}function te(t){delete Yt[t.pointerId]}function ee(t,e){if(e.pointerType!==(e.MSPOINTER_TYPE_MOUSE||"mouse")){for(var i in e.touches=[],Yt)e.touches.push(Yt[i]);e.changedTouches=[e],t(e)}}var ie=200;function ne(t,i){t.addEventListener("dblclick",i);var n,o=0;function e(t){var e;1!==t.detail?n=t.detail:"mouse"===t.pointerType||t.sourceCapabilities&&!t.sourceCapabilities.firesTouchEvents||((e=Ne(t)).some(function(t){return t instanceof HTMLLabelElement&&t.attributes.for})&&!e.some(function(t){return t instanceof HTMLInputElement||t instanceof HTMLSelectElement})||((e=Date.now())-o<=ie?2===++n&&i(function(t){var e,i,n={};for(i in t)e=t[i],n[i]=e&&e.bind?e.bind(t):e;return(t=n).type="dblclick",n.detail=2,n.isTrusted=!1,n._simulated=!0,n}(t)):n=1,o=e))}return t.addEventListener("click",e),{dblclick:i,simDblclick:e}}var oe,se,re,ae,he,le,ue=we(["transform","webkitTransform","OTransform","MozTransform","msTransform"]),ce=we(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),de="webkitTransition"===ce||"OTransition"===ce?ce+"End":"transitionend";function _e(t){return"string"==typeof t?document.getElementById(t):t}function pe(t,e){var i=t.style[e]||t.currentStyle&&t.currentStyle[e];return"auto"===(i=i&&"auto"!==i||!document.defaultView?i:(t=document.defaultView.getComputedStyle(t,null))?t[e]:null)?null:i}function P(t,e,i){t=document.createElement(t);return t.className=e||"",i&&i.appendChild(t),t}function T(t){var e=t.parentNode;e&&e.removeChild(t)}function me(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function fe(t){var e=t.parentNode;e&&e.lastChild!==t&&e.appendChild(t)}function ge(t){var e=t.parentNode;e&&e.firstChild!==t&&e.insertBefore(t,e.firstChild)}function ve(t,e){return void 0!==t.classList?t.classList.contains(e):0<(t=xe(t)).length&&new RegExp("(^|\\s)"+e+"(\\s|$)").test(t)}function M(t,e){var i;if(void 0!==t.classList)for(var n=F(e),o=0,s=n.length;othis.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,e){this._enforcingBounds=!0;var i=this.getCenter(),t=this._limitCenter(i,this._zoom,g(t));return i.equals(t)||this.panTo(t,e),this._enforcingBounds=!1,this},panInside:function(t,e){var i=m((e=e||{}).paddingTopLeft||e.padding||[0,0]),n=m(e.paddingBottomRight||e.padding||[0,0]),o=this.project(this.getCenter()),t=this.project(t),s=this.getPixelBounds(),i=_([s.min.add(i),s.max.subtract(n)]),s=i.getSize();return i.contains(t)||(this._enforcingBounds=!0,n=t.subtract(i.getCenter()),i=i.extend(t).getSize().subtract(s),o.x+=n.x<0?-i.x:i.x,o.y+=n.y<0?-i.y:i.y,this.panTo(this.unproject(o),e),this._enforcingBounds=!1),this},invalidateSize:function(t){if(!this._loaded)return this;t=l({animate:!1,pan:!0},!0===t?{animate:!0}:t);var e=this.getSize(),i=(this._sizeChanged=!0,this._lastCenter=null,this.getSize()),n=e.divideBy(2).round(),o=i.divideBy(2).round(),n=n.subtract(o);return n.x||n.y?(t.animate&&t.pan?this.panBy(n):(t.pan&&this._rawPanBy(n),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(a(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize:e,newSize:i})):this},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire("viewreset"),this._stop()},locate:function(t){var e,i;return t=this._locateOptions=l({timeout:1e4,watch:!1},t),"geolocation"in navigator?(e=a(this._handleGeolocationResponse,this),i=a(this._handleGeolocationError,this),t.watch?this._locationWatchId=navigator.geolocation.watchPosition(e,i,t):navigator.geolocation.getCurrentPosition(e,i,t)):this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var e;this._container._leaflet_id&&(e=t.code,t=t.message||(1===e?"permission denied":2===e?"position unavailable":"timeout"),this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:e,message:"Geolocation error: "+t+"."}))},_handleGeolocationResponse:function(t){if(this._container._leaflet_id){var e,i,n=new v(t.coords.latitude,t.coords.longitude),o=n.toBounds(2*t.coords.accuracy),s=this._locateOptions,r=(s.setView&&(e=this.getBoundsZoom(o),this.setView(n,s.maxZoom?Math.min(e,s.maxZoom):e)),{latlng:n,bounds:o,timestamp:t.timestamp});for(i in t.coords)"number"==typeof t.coords[i]&&(r[i]=t.coords[i]);this.fire("locationfound",r)}},addHandler:function(t,e){return e&&(e=this[t]=new e(this),this._handlers.push(e),this.options[t]&&e.enable()),this},remove:function(){if(this._initEvents(!0),this.options.maxBounds&&this.off("moveend",this._panInsideMaxBounds),this._containerId!==this._container._leaflet_id)throw new Error("Map container is being reused by another instance");try{delete this._container._leaflet_id,delete this._containerId}catch(t){this._container._leaflet_id=void 0,this._containerId=void 0}for(var t in void 0!==this._locationWatchId&&this.stopLocate(),this._stop(),T(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._resizeRequest&&(r(this._resizeRequest),this._resizeRequest=null),this._clearHandlers(),this._loaded&&this.fire("unload"),this._layers)this._layers[t].remove();for(t in this._panes)T(this._panes[t]);return this._layers=[],this._panes=[],delete this._mapPane,delete this._renderer,this},createPane:function(t,e){e=P("div","leaflet-pane"+(t?" leaflet-"+t.replace("Pane","")+"-pane":""),e||this._mapPane);return t&&(this._panes[t]=e),e},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter.clone():this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds();return new s(this.unproject(t.getBottomLeft()),this.unproject(t.getTopRight()))},getMinZoom:function(){return void 0===this.options.minZoom?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return void 0===this.options.maxZoom?void 0===this._layersMaxZoom?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,e,i){t=g(t),i=m(i||[0,0]);var n=this.getZoom()||0,o=this.getMinZoom(),s=this.getMaxZoom(),r=t.getNorthWest(),t=t.getSouthEast(),i=this.getSize().subtract(i),t=_(this.project(t,n),this.project(r,n)).getSize(),r=b.any3d?this.options.zoomSnap:1,a=i.x/t.x,i=i.y/t.y,t=e?Math.max(a,i):Math.min(a,i),n=this.getScaleZoom(t,n);return r&&(n=Math.round(n/(r/100))*(r/100),n=e?Math.ceil(n/r)*r:Math.floor(n/r)*r),Math.max(o,Math.min(s,n))},getSize:function(){return this._size&&!this._sizeChanged||(this._size=new p(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(t,e){t=this._getTopLeftPoint(t,e);return new f(t,t.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(t){return this.options.crs.getProjectedBounds(void 0===t?this.getZoom():t)},getPane:function(t){return"string"==typeof t?this._panes[t]:t},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t,e){var i=this.options.crs;return e=void 0===e?this._zoom:e,i.scale(t)/i.scale(e)},getScaleZoom:function(t,e){var i=this.options.crs,t=(e=void 0===e?this._zoom:e,i.zoom(t*i.scale(e)));return isNaN(t)?1/0:t},project:function(t,e){return e=void 0===e?this._zoom:e,this.options.crs.latLngToPoint(w(t),e)},unproject:function(t,e){return e=void 0===e?this._zoom:e,this.options.crs.pointToLatLng(m(t),e)},layerPointToLatLng:function(t){t=m(t).add(this.getPixelOrigin());return this.unproject(t)},latLngToLayerPoint:function(t){return this.project(w(t))._round()._subtract(this.getPixelOrigin())},wrapLatLng:function(t){return this.options.crs.wrapLatLng(w(t))},wrapLatLngBounds:function(t){return this.options.crs.wrapLatLngBounds(g(t))},distance:function(t,e){return this.options.crs.distance(w(t),w(e))},containerPointToLayerPoint:function(t){return m(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return m(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){t=this.containerPointToLayerPoint(m(t));return this.layerPointToLatLng(t)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(w(t)))},mouseEventToContainerPoint:function(t){return De(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){t=this._container=_e(t);if(!t)throw new Error("Map container not found.");if(t._leaflet_id)throw new Error("Map container is already initialized.");S(t,"scroll",this._onScroll,this),this._containerId=h(t)},_initLayout:function(){var t=this._container,e=(this._fadeAnimated=this.options.fadeAnimation&&b.any3d,M(t,"leaflet-container"+(b.touch?" leaflet-touch":"")+(b.retina?" leaflet-retina":"")+(b.ielt9?" leaflet-oldie":"")+(b.safari?" leaflet-safari":"")+(this._fadeAnimated?" leaflet-fade-anim":"")),pe(t,"position"));"absolute"!==e&&"relative"!==e&&"fixed"!==e&&"sticky"!==e&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),Z(this._mapPane,new p(0,0)),this.createPane("tilePane"),this.createPane("overlayPane"),this.createPane("shadowPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(M(t.markerPane,"leaflet-zoom-hide"),M(t.shadowPane,"leaflet-zoom-hide"))},_resetView:function(t,e,i){Z(this._mapPane,new p(0,0));var n=!this._loaded,o=(this._loaded=!0,e=this._limitZoom(e),this.fire("viewprereset"),this._zoom!==e);this._moveStart(o,i)._move(t,e)._moveEnd(o),this.fire("viewreset"),n&&this.fire("load")},_moveStart:function(t,e){return t&&this.fire("zoomstart"),e||this.fire("movestart"),this},_move:function(t,e,i,n){void 0===e&&(e=this._zoom);var o=this._zoom!==e;return this._zoom=e,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),n?i&&i.pinch&&this.fire("zoom",i):((o||i&&i.pinch)&&this.fire("zoom",i),this.fire("move",i)),this},_moveEnd:function(t){return t&&this.fire("zoomend"),this.fire("moveend")},_stop:function(){return r(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){Z(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(t){this._targets={};var e=t?k:S;e((this._targets[h(this._container)]=this)._container,"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress keydown keyup",this._handleDOMEvent,this),this.options.trackResize&&e(window,"resize",this._onResize,this),b.any3d&&this.options.transform3DLimit&&(t?this.off:this.on).call(this,"moveend",this._onMoveEnd)},_onResize:function(){r(this._resizeRequest),this._resizeRequest=x(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,e){for(var i,n=[],o="mouseout"===e||"mouseover"===e,s=t.target||t.srcElement,r=!1;s;){if((i=this._targets[h(s)])&&("click"===e||"preclick"===e)&&this._draggableMoved(i)){r=!0;break}if(i&&i.listens(e,!0)){if(o&&!We(s,t))break;if(n.push(i),o)break}if(s===this._container)break;s=s.parentNode}return n=n.length||r||o||!this.listens(e,!0)?n:[this]},_isClickDisabled:function(t){for(;t&&t!==this._container;){if(t._leaflet_disable_click)return!0;t=t.parentNode}},_handleDOMEvent:function(t){var e,i=t.target||t.srcElement;!this._loaded||i._leaflet_disable_events||"click"===t.type&&this._isClickDisabled(i)||("mousedown"===(e=t.type)&&Me(i),this._fireDOMEvent(t,e))},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,e,i){"click"===t.type&&((a=l({},t)).type="preclick",this._fireDOMEvent(a,a.type,i));var n=this._findEventTargets(t,e);if(i){for(var o=[],s=0;sthis.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(e),n=this._getCenterOffset(t)._divideBy(1-1/n);if(!0!==i.animate&&!this.getSize().contains(n))return!1;x(function(){this._moveStart(!0,i.noMoveStart||!1)._animateZoom(t,e,!0)},this)}return!0},_animateZoom:function(t,e,i,n){this._mapPane&&(i&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=e,M(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:e,noUpdate:n}),this._tempFireZoomEvent||(this._tempFireZoomEvent=this._zoom!==this._animateToZoom),this._move(this._animateToCenter,this._animateToZoom,void 0,!0),setTimeout(a(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&z(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom,void 0,!0),this._tempFireZoomEvent&&this.fire("zoom"),delete this._tempFireZoomEvent,this.fire("move"),this._moveEnd(!0))}});function Ue(t){return new B(t)}var B=et.extend({options:{position:"topright"},initialize:function(t){c(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var e=this._map;return e&&e.removeControl(this),this.options.position=t,e&&e.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var e=this._container=this.onAdd(t),i=this.getPosition(),t=t._controlCorners[i];return M(e,"leaflet-control"),-1!==i.indexOf("bottom")?t.insertBefore(e,t.firstChild):t.appendChild(e),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(T(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0",e=document.createElement("div");return e.innerHTML=t,e.firstChild},_addItem:function(t){var e,i=document.createElement("label"),n=this._map.hasLayer(t.layer),n=(t.overlay?((e=document.createElement("input")).type="checkbox",e.className="leaflet-control-layers-selector",e.defaultChecked=n):e=this._createRadioElement("leaflet-base-layers_"+h(this),n),this._layerControlInputs.push(e),e.layerId=h(t.layer),S(e,"click",this._onInputClick,this),document.createElement("span")),o=(n.innerHTML=" "+t.name,document.createElement("span"));return i.appendChild(o),o.appendChild(e),o.appendChild(n),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(i),this._checkDisabledLayers(),i},_onInputClick:function(){if(!this._preventClick){var t,e,i=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=i.length-1;0<=s;s--)t=i[s],e=this._getLayer(t.layerId).layer,t.checked?n.push(e):t.checked||o.push(e);for(s=0;se.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expandSafely:function(){var t=this._section,e=(this._preventClick=!0,S(t,"click",O),this.expand(),this);setTimeout(function(){k(t,"click",O),e._preventClick=!1})}})),qe=B.extend({options:{position:"topleft",zoomInText:'',zoomInTitle:"Zoom in",zoomOutText:'',zoomOutTitle:"Zoom out"},onAdd:function(t){var e="leaflet-control-zoom",i=P("div",e+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,e+"-in",i,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,e+"-out",i,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),i},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,e,i,n,o){i=P("a",i,n);return i.innerHTML=t,i.href="#",i.title=e,i.setAttribute("role","button"),i.setAttribute("aria-label",e),Ie(i),S(i,"click",Re),S(i,"click",o,this),S(i,"click",this._refocusOnMap,this),i},_updateDisabled:function(){var t=this._map,e="leaflet-disabled";z(this._zoomInButton,e),z(this._zoomOutButton,e),this._zoomInButton.setAttribute("aria-disabled","false"),this._zoomOutButton.setAttribute("aria-disabled","false"),!this._disabled&&t._zoom!==t.getMinZoom()||(M(this._zoomOutButton,e),this._zoomOutButton.setAttribute("aria-disabled","true")),!this._disabled&&t._zoom!==t.getMaxZoom()||(M(this._zoomInButton,e),this._zoomInButton.setAttribute("aria-disabled","true"))}}),Ge=(A.mergeOptions({zoomControl:!0}),A.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new qe,this.addControl(this.zoomControl))}),B.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var e="leaflet-control-scale",i=P("div",e),n=this.options;return this._addScales(n,e+"-line",i),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),i},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,e,i){t.metric&&(this._mScale=P("div",e,i)),t.imperial&&(this._iScale=P("div",e,i))},_update:function(){var t=this._map,e=t.getSize().y/2,t=t.distance(t.containerPointToLatLng([0,e]),t.containerPointToLatLng([this.options.maxWidth,e]));this._updateScales(t)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var e=this._getRoundNum(t);this._updateScale(this._mScale,e<1e3?e+" m":e/1e3+" km",e/t)},_updateImperial:function(t){var e,i,t=3.2808399*t;5280'+(b.inlineSvg?' ':"")+"Leaflet"},initialize:function(t){c(this,t),this._attributions={}},onAdd:function(t){for(var e in(t.attributionControl=this)._container=P("div","leaflet-control-attribution"),Ie(this._container),t._layers)t._layers[e].getAttribution&&this.addAttribution(t._layers[e].getAttribution());return this._update(),t.on("layeradd",this._addAttribution,this),this._container},onRemove:function(t){t.off("layeradd",this._addAttribution,this)},_addAttribution:function(t){t.layer.getAttribution&&(this.addAttribution(t.layer.getAttribution()),t.layer.once("remove",function(){this.removeAttribution(t.layer.getAttribution())},this))},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t,e=[];for(t in this._attributions)this._attributions[t]&&e.push(t);var i=[];this.options.prefix&&i.push(this.options.prefix),e.length&&i.push(e.join(", ")),this._container.innerHTML=i.join(' ')}}}),n=(A.mergeOptions({attributionControl:!0}),A.addInitHook(function(){this.options.attributionControl&&(new Ke).addTo(this)}),B.Layers=Ve,B.Zoom=qe,B.Scale=Ge,B.Attribution=Ke,Ue.layers=function(t,e,i){return new Ve(t,e,i)},Ue.zoom=function(t){return new qe(t)},Ue.scale=function(t){return new Ge(t)},Ue.attribution=function(t){return new Ke(t)},et.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}})),ft=(n.addTo=function(t,e){return t.addHandler(e,this),this},{Events:e}),Ye=b.touch?"touchstart mousedown":"mousedown",Xe=it.extend({options:{clickTolerance:3},initialize:function(t,e,i,n){c(this,n),this._element=t,this._dragStartTarget=e||t,this._preventOutline=i},enable:function(){this._enabled||(S(this._dragStartTarget,Ye,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(Xe._dragging===this&&this.finishDrag(!0),k(this._dragStartTarget,Ye,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){var e,i;this._enabled&&(this._moved=!1,ve(this._element,"leaflet-zoom-anim")||(t.touches&&1!==t.touches.length?Xe._dragging===this&&this.finishDrag():Xe._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((Xe._dragging=this)._preventOutline&&Me(this._element),Le(),re(),this._moving||(this.fire("down"),i=t.touches?t.touches[0]:t,e=Ce(this._element),this._startPoint=new p(i.clientX,i.clientY),this._startPos=Pe(this._element),this._parentScale=Ze(e),i="mousedown"===t.type,S(document,i?"mousemove":"touchmove",this._onMove,this),S(document,i?"mouseup":"touchend touchcancel",this._onUp,this)))))},_onMove:function(t){var e;this._enabled&&(t.touches&&1e&&(i.push(t[n]),o=n);oe.max.x&&(i|=2),t.ye.max.y&&(i|=8),i}function ri(t,e,i,n){var o=e.x,e=e.y,s=i.x-o,r=i.y-e,a=s*s+r*r;return 0this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()t.y!=n.y>t.y&&t.x<(n.x-i.x)*(t.y-i.y)/(n.y-i.y)+i.x&&(l=!l);return l||yi.prototype._containsPoint.call(this,t,!0)}});var wi=ci.extend({initialize:function(t,e){c(this,e),this._layers={},t&&this.addData(t)},addData:function(t){var e,i,n,o=d(t)?t:t.features;if(o){for(e=0,i=o.length;es.x&&(r=i.x+a-s.x+o.x),i.x-r-n.x<(a=0)&&(r=i.x-n.x),i.y+e+o.y>s.y&&(a=i.y+e-s.y+o.y),i.y-a-n.y<0&&(a=i.y-n.y),(r||a)&&(this.options.keepInView&&(this._autopanning=!0),t.fire("autopanstart").panBy([r,a]))))},_getAnchor:function(){return m(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}})),Ii=(A.mergeOptions({closePopupOnClick:!0}),A.include({openPopup:function(t,e,i){return this._initOverlay(Bi,t,e,i).openOn(this),this},closePopup:function(t){return(t=arguments.length?t:this._popup)&&t.close(),this}}),o.include({bindPopup:function(t,e){return this._popup=this._initOverlay(Bi,this._popup,t,e),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t){return this._popup&&(this instanceof ci||(this._popup._source=this),this._popup._prepareOpen(t||this._latlng)&&this._popup.openOn(this._map)),this},closePopup:function(){return this._popup&&this._popup.close(),this},togglePopup:function(){return this._popup&&this._popup.toggle(this),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var e;this._popup&&this._map&&(Re(t),e=t.layer||t.target,this._popup._source!==e||e instanceof fi?(this._popup._source=e,this.openPopup(t.latlng)):this._map.hasLayer(this._popup)?this.closePopup():this.openPopup(t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}}),Ai.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,opacity:.9},onAdd:function(t){Ai.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&(this.addEventParent(this._source),this._source.fire("tooltipopen",{tooltip:this},!0))},onRemove:function(t){Ai.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&(this.removeEventParent(this._source),this._source.fire("tooltipclose",{tooltip:this},!0))},getEvents:function(){var t=Ai.prototype.getEvents.call(this);return this.options.permanent||(t.preclick=this.close),t},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=P("div",t),this._container.setAttribute("role","tooltip"),this._container.setAttribute("id","leaflet-tooltip-"+h(this))},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var e,i=this._map,n=this._container,o=i.latLngToContainerPoint(i.getCenter()),i=i.layerPointToContainerPoint(t),s=this.options.direction,r=n.offsetWidth,a=n.offsetHeight,h=m(this.options.offset),l=this._getAnchor(),i="top"===s?(e=r/2,a):"bottom"===s?(e=r/2,0):(e="center"===s?r/2:"right"===s?0:"left"===s?r:i.xthis.options.maxZoom||nthis.options.maxZoom||void 0!==this.options.minZoom&&oi.max.x)||!e.wrapLat&&(t.yi.max.y))return!1}return!this.options.bounds||(e=this._tileCoordsToBounds(t),g(this.options.bounds).overlaps(e))},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var e=this._map,i=this.getTileSize(),n=t.scaleBy(i),i=n.add(i);return[e.unproject(n,t.z),e.unproject(i,t.z)]},_tileCoordsToBounds:function(t){t=this._tileCoordsToNwSe(t),t=new s(t[0],t[1]);return t=this.options.noWrap?t:this._map.wrapLatLngBounds(t)},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var t=t.split(":"),e=new p(+t[0],+t[1]);return e.z=+t[2],e},_removeTile:function(t){var e=this._tiles[t];e&&(T(e.el),delete this._tiles[t],this.fire("tileunload",{tile:e.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){M(t,"leaflet-tile");var e=this.getTileSize();t.style.width=e.x+"px",t.style.height=e.y+"px",t.onselectstart=u,t.onmousemove=u,b.ielt9&&this.options.opacity<1&&C(t,this.options.opacity)},_addTile:function(t,e){var i=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),a(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&x(a(this._tileReady,this,t,null,o)),Z(o,i),this._tiles[n]={el:o,coords:t,current:!0},e.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,e,i){e&&this.fire("tileerror",{error:e,tile:i,coords:t});var n=this._tileCoordsToKey(t);(i=this._tiles[n])&&(i.loaded=+new Date,this._map._fadeAnimated?(C(i.el,0),r(this._fadeFrame),this._fadeFrame=x(this._updateOpacity,this)):(i.active=!0,this._pruneTiles()),e||(M(i.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:i.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),b.ielt9||!this._map._fadeAnimated?x(this._pruneTiles,this):setTimeout(a(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var e=new p(this._wrapX?H(t.x,this._wrapX):t.x,this._wrapY?H(t.y,this._wrapY):t.y);return e.z=t.z,e},_pxBoundsToTileRange:function(t){var e=this.getTileSize();return new f(t.min.unscaleBy(e).floor(),t.max.unscaleBy(e).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var Di=Ni.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1,referrerPolicy:!1},initialize:function(t,e){this._url=t,(e=c(this,e)).detectRetina&&b.retina&&0')}}catch(t){}return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}(),zt={_initContainer:function(){this._container=P("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(Wi.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var e=t._container=Vi("shape");M(e,"leaflet-vml-shape "+(this.options.className||"")),e.coordsize="1 1",t._path=Vi("path"),e.appendChild(t._path),this._updateStyle(t),this._layers[h(t)]=t},_addPath:function(t){var e=t._container;this._container.appendChild(e),t.options.interactive&&t.addInteractiveTarget(e)},_removePath:function(t){var e=t._container;T(e),t.removeInteractiveTarget(e),delete this._layers[h(t)]},_updateStyle:function(t){var e=t._stroke,i=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(e=e||(t._stroke=Vi("stroke")),o.appendChild(e),e.weight=n.weight+"px",e.color=n.color,e.opacity=n.opacity,n.dashArray?e.dashStyle=d(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):e.dashStyle="",e.endcap=n.lineCap.replace("butt","flat"),e.joinstyle=n.lineJoin):e&&(o.removeChild(e),t._stroke=null),n.fill?(i=i||(t._fill=Vi("fill")),o.appendChild(i),i.color=n.fillColor||n.color,i.opacity=n.fillOpacity):i&&(o.removeChild(i),t._fill=null)},_updateCircle:function(t){var e=t._point.round(),i=Math.round(t._radius),n=Math.round(t._radiusY||i);this._setPath(t,t._empty()?"M0 0":"AL "+e.x+","+e.y+" "+i+","+n+" 0,23592600")},_setPath:function(t,e){t._path.v=e},_bringToFront:function(t){fe(t._container)},_bringToBack:function(t){ge(t._container)}},qi=b.vml?Vi:ct,Gi=Wi.extend({_initContainer:function(){this._container=qi("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=qi("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){T(this._container),k(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_update:function(){var t,e,i;this._map._animatingZoom&&this._bounds||(Wi.prototype._update.call(this),e=(t=this._bounds).getSize(),i=this._container,this._svgSize&&this._svgSize.equals(e)||(this._svgSize=e,i.setAttribute("width",e.x),i.setAttribute("height",e.y)),Z(i,t.min),i.setAttribute("viewBox",[t.min.x,t.min.y,e.x,e.y].join(" ")),this.fire("update"))},_initPath:function(t){var e=t._path=qi("path");t.options.className&&M(e,t.options.className),t.options.interactive&&M(e,"leaflet-interactive"),this._updateStyle(t),this._layers[h(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){T(t._path),t.removeInteractiveTarget(t._path),delete this._layers[h(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var e=t._path,t=t.options;e&&(t.stroke?(e.setAttribute("stroke",t.color),e.setAttribute("stroke-opacity",t.opacity),e.setAttribute("stroke-width",t.weight),e.setAttribute("stroke-linecap",t.lineCap),e.setAttribute("stroke-linejoin",t.lineJoin),t.dashArray?e.setAttribute("stroke-dasharray",t.dashArray):e.removeAttribute("stroke-dasharray"),t.dashOffset?e.setAttribute("stroke-dashoffset",t.dashOffset):e.removeAttribute("stroke-dashoffset")):e.setAttribute("stroke","none"),t.fill?(e.setAttribute("fill",t.fillColor||t.color),e.setAttribute("fill-opacity",t.fillOpacity),e.setAttribute("fill-rule",t.fillRule||"evenodd")):e.setAttribute("fill","none"))},_updatePoly:function(t,e){this._setPath(t,dt(t._parts,e))},_updateCircle:function(t){var e=t._point,i=Math.max(Math.round(t._radius),1),n="a"+i+","+(Math.max(Math.round(t._radiusY),1)||i)+" 0 1,0 ",e=t._empty()?"M0 0":"M"+(e.x-i)+","+e.y+n+2*i+",0 "+n+2*-i+",0 ";this._setPath(t,e)},_setPath:function(t,e){t._path.setAttribute("d",e)},_bringToFront:function(t){fe(t._path)},_bringToBack:function(t){ge(t._path)}});function Ki(t){return b.svg||b.vml?new Gi(t):null}b.vml&&Gi.include(zt),A.include({getRenderer:function(t){t=(t=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer)||(this._renderer=this._createRenderer());return this.hasLayer(t)||this.addLayer(t),t},_getPaneRenderer:function(t){var e;return"overlayPane"!==t&&void 0!==t&&(void 0===(e=this._paneRenderers[t])&&(e=this._createRenderer({pane:t}),this._paneRenderers[t]=e),e)},_createRenderer:function(t){return this.options.preferCanvas&&Ui(t)||Ki(t)}});var Yi=xi.extend({initialize:function(t,e){xi.prototype.initialize.call(this,this._boundsToLatLngs(t),e)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=g(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});Gi.create=qi,Gi.pointsToPath=dt,wi.geometryToLayer=bi,wi.coordsToLatLng=Li,wi.coordsToLatLngs=Ti,wi.latLngToCoords=Mi,wi.latLngsToCoords=zi,wi.getFeature=Ci,wi.asFeature=Zi,A.mergeOptions({boxZoom:!0});var _t=n.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){S(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){k(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){T(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),re(),Le(),this._startPoint=this._map.mouseEventToContainerPoint(t),S(document,{contextmenu:Re,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=P("div","leaflet-zoom-box",this._container),M(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var t=new f(this._point,this._startPoint),e=t.getSize();Z(this._box,t.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(T(this._box),z(this._container,"leaflet-crosshair")),ae(),Te(),k(document,{contextmenu:Re,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){1!==t.which&&1!==t.button||(this._finish(),this._moved&&(this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(a(this._resetState,this),0),t=new s(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point)),this._map.fitBounds(t).fire("boxzoomend",{boxZoomBounds:t})))},_onKeyDown:function(t){27===t.keyCode&&(this._finish(),this._clearDeferredResetState(),this._resetState())}}),Ct=(A.addInitHook("addHandler","boxZoom",_t),A.mergeOptions({doubleClickZoom:!0}),n.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var e=this._map,i=e.getZoom(),n=e.options.zoomDelta,i=t.originalEvent.shiftKey?i-n:i+n;"center"===e.options.doubleClickZoom?e.setZoom(i):e.setZoomAround(t.containerPoint,i)}})),Zt=(A.addInitHook("addHandler","doubleClickZoom",Ct),A.mergeOptions({dragging:!0,inertia:!0,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0}),n.extend({addHooks:function(){var t;this._draggable||(t=this._map,this._draggable=new Xe(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))),M(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){z(this._map._container,"leaflet-grab"),z(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t,e=this._map;e._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity?(t=g(this._map.options.maxBounds),this._offsetLimit=_(this._map.latLngToContainerPoint(t.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(t.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))):this._offsetLimit=null,e.fire("movestart").fire("dragstart"),e.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){var e,i;this._map.options.inertia&&(e=this._lastTime=+new Date,i=this._lastPos=this._draggable._absPos||this._draggable._newPos,this._positions.push(i),this._times.push(e),this._prunePositions(e)),this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1e.max.x&&(t.x=this._viscousLimit(t.x,e.max.x)),t.y>e.max.y&&(t.y=this._viscousLimit(t.y,e.max.y)),this._draggable._newPos=this._draggable._startPos.add(t))},_onPreDragWrap:function(){var t=this._worldWidth,e=Math.round(t/2),i=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-e+i)%t+e-i,n=(n+e+i)%t-e-i,t=Math.abs(o+i)e.getMaxZoom()&&1 Date: Thu, 8 Feb 2024 15:58:52 +0100 Subject: [PATCH 37/43] use dune-site --- dune-project | 9 ++- example/css_path.ml | 14 ++++ example/dune | 13 +++- example/map.html | 7 +- example/{main.ml => script.ml} | 4 + leaflet.opam | 1 + src/dune | 20 ++++- src/vendor/images/layers-2x.png | Bin 0 -> 1259 bytes src/vendor/images/layers.png | Bin 0 -> 696 bytes src/vendor/images/marker-icon-2x.png | Bin 0 -> 2464 bytes src/vendor/images/marker-icon.png | Bin 0 -> 1466 bytes src/vendor/images/marker-shadow.png | Bin 0 -> 618 bytes {example => src/vendor}/leaflet.css | 111 ++++++++++++++++----------- src/{ => vendor}/leaflet.js | 0 14 files changed, 126 insertions(+), 53 deletions(-) create mode 100644 example/css_path.ml rename example/{main.ml => script.ml} (72%) create mode 100644 src/vendor/images/layers-2x.png create mode 100644 src/vendor/images/layers.png create mode 100644 src/vendor/images/marker-icon-2x.png create mode 100644 src/vendor/images/marker-icon.png create mode 100644 src/vendor/images/marker-shadow.png rename {example => src/vendor}/leaflet.css (83%) rename src/{ => vendor}/leaflet.js (100%) diff --git a/dune-project b/dune-project index 896dd1a..41f5cea 100644 --- a/dune-project +++ b/dune-project @@ -1,6 +1,7 @@ (lang dune 2.9) - -(implicit_transitive_deps false) +(using dune_site 0.1) +;uncomment when fixed: https://github.com/ocaml/dune/issues/9661 +;(implicit_transitive_deps false) (name leaflet) @@ -31,5 +32,7 @@ (depends brr js_of_ocaml + dune-site (ocaml - (>= 4.08)))) + (>= 4.08))) + (sites (share css) (share images))) diff --git a/example/css_path.ml b/example/css_path.ml new file mode 100644 index 0000000..96a5634 --- /dev/null +++ b/example/css_path.ml @@ -0,0 +1,14 @@ +(* get leaflet.css path from dune-site *) + +let dune_site = List.filter Sys.file_exists Mysites.Sites.css + +let lookup_file filename = + List.find_map + (fun dir -> + let filename' = Filename.concat dir filename in + if Sys.file_exists filename' then Some filename' else None ) + dune_site + +let leaflet_css = lookup_file "leaflet.css" |> Option.get + +let () = Format.printf "%s@." leaflet_css diff --git a/example/dune b/example/dune index b868e46..1e537ac 100644 --- a/example/dune +++ b/example/dune @@ -1,5 +1,14 @@ (executable - (name main) - (modules main) + (name css_path) + (modules css_path mysites) + (libraries dune-site)) + +(generate_sites_module + (module mysites) + (sites leaflet)) + +(executable + (name script) + (modules script) (libraries brr leaflet) (modes js)) diff --git a/example/map.html b/example/map.html index 341173f..053dd17 100644 --- a/example/map.html +++ b/example/map.html @@ -1,12 +1,15 @@ + - +
-
+ +
diff --git a/example/main.ml b/example/script.ml similarity index 72% rename from example/main.ml rename to example/script.ml index 5fbe7c4..4dfe92f 100644 --- a/example/main.ml +++ b/example/script.ml @@ -1,3 +1,7 @@ +(* this file will be compiled to js + you can then open map.html to see a simple page with a map loaded + by this script *) + (* create map *) let map = Leaflet.Map.create_on "map" diff --git a/leaflet.opam b/leaflet.opam index 1b6ae70..d4db64e 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -18,6 +18,7 @@ depends: [ "dune" {>= "2.9"} "brr" "js_of_ocaml" + "dune-site" "ocaml" {>= "4.08"} "odoc" {with-doc} ] diff --git a/src/dune b/src/dune index c29d930..e34b390 100644 --- a/src/dune +++ b/src/dune @@ -4,4 +4,22 @@ (private_modules global) (libraries brr) (js_of_ocaml - (javascript_files leaflet.js))) + (javascript_files vendor/leaflet.js))) + +(install + (section + (site + (leaflet css))) + (files + (vendor/leaflet.css as leaflet.css))) + +(install + (section + (site + (leaflet images))) + (files + (vendor/images/layers-2x.png as images/layers-2x.png) + (vendor/images/layers.png as images/layers.png) + (vendor/images/marker-icon-2x.png as images/marker-icon-2x.png) + (vendor/images/marker-icon.png as images/marker-icon.png) + (vendor/images/marker-shadow.png as images/marker-shadow.png))) diff --git a/src/vendor/images/layers-2x.png b/src/vendor/images/layers-2x.png new file mode 100644 index 0000000000000000000000000000000000000000..200c333dca9652ac4cba004d609e5af4eee168c1 GIT binary patch literal 1259 zcmeAS@N?(olHy`uVBq!ia0y~yU@!q;4i*LmhWx_I2@DJ@n><|{Ln;`Pe)y|cT4BSrpMM7AKE|dn|XR+k!t#k(tv`Q zFW(sEd!8~#>$+9`f9l__#fF!KZ}B_rzo8eC{r}xGzO@x)!A}C+%Y(`<1s-2^LiGH- zNefThzU1_3Qe}!q>B&sRiQ8E#H9j`Wp1zeElOM1<_xPqG{7q&i{}sRA|NWDBa`yhi zf4~1}Z!&l?D{`K~v~Df`g0pk31-#L={QUP&^~BTfPt276eJZ4F#OLLkrWm<1w?G}$K(_Zg>&?>%7rSDWy?-oPVGDw+3f6ddKzommMznMtmE1m^mE;|X)^@3r5^M>q%(7WwwkhRUVZzX zFui*B_UL;{ERE{7ySzCa{A5c-^`03^s-Cnw)fD`#!?J7Jk{=GMTBd1ws=RS{H7RMA z+lH2N3m&&zxMt!%-Q)BVRe@_$r#$1#RlV@>f}~i)v%B7(D}^uiKE0`=J9&~rL}git za^vjh=XaOCc>eeO>kuD~_nyZSSrR*HoRZ?^jT=9HS|#-C z#I0=$9oqx1b}%c7@V%LR;e=gTTa&Q*O*Q|E%7{caZdK)_+ZJf zZ?&H!g%0t3zQ`e9eahh1=NZBi3YOTd+htU}IKfpW%e~b`fYbPb(yyJ0eX|!$;Jmtc zpGlI(Uq{=OPOf@MjvXyZfAUxkxkT|?T2R1T7_4W$NpIDXdncV=-Og(5O3XcC)5tQ> zz+Ah^=e$i`pnF#TudS&IcRlWTsKE8W$-*hoo%u=2$;`|LE*k2wcM@{W?B28Hj1!|( z?&`3_D`smL6xn7gD*L#dPAd}*D+qeymA_@1k^7b7fk)o?9(Qdv5?I?{*Qdo6H_a$Z zWx4ILe&t;!1-}-TBu7TxOI@rh@5%8t*~M7);;#tq)bxD@K>`uh2LySGU20__qc2Mz zz5e8&(8Q{b_nT$qIxJK3ZwNANm$G;z+!`QW&+ygqZIXsCQ=*b?Q`wxE@t%9{h$R(y z`}7A0eZ8=B>r+-n=MV*-1+Ej;cKH>13)vbyyUbGSW~KP1V^g_>mQb1#clPCv9d}vs ze&jIq>z1(p^?bgvyl$yv;Vr)mizp0?3uUtD~sA1FSi+%x^t@XE}h@-tYzk9 zqoeJq#fQ#h%zQM#GO;LXnVpKdkC%5qo68}Ws3tQNA+-xadlV-caB*y5$@NebP0l+XkKIZj$K literal 0 HcmV?d00001 diff --git a/src/vendor/images/layers.png b/src/vendor/images/layers.png new file mode 100644 index 0000000000000000000000000000000000000000..1a72e5784b2b456eac5d7670738db80697af3377 GIT binary patch literal 696 zcmeAS@N?(olHy`uVBq!ia0y~yV2}b~4i*Lm24?3LR|W>AdQTU}kP61$5aS9JMv;5A zx9={r3D-Qo$}jd-@Kme(q}h{gk8N9f^YEHSI?4X$wi&*^XXUqVf93n@6)G0|HB0O+ z{oGRd;!&;aKiPjre@~N1y8by_{oP(ApF5A&Z+bmlV3plXXQ4Q^(0Q+y~?G3 z!a`R6-Bzb}>nxoMS3g;|c>CL9(`O!9VDQ7}^1l9i({>+QJ4%7S^9P-Qtwc)jUmWjVlF-6H4cVyjqg@ zMm}=+(G^1+f9k%t3*NyNhGDITISixbZs=XtX?<#@#To^} zllR&yC7Q0b2+Ufee$_3@VyDHEwjITj6hhx>ORdzOd~VN~YpdKO9dmD=@;Ir&?!Ka0 ze9@!>sms1^+w^n(%oWF3dR*t__&0jzGw-8qqez~?-<4~x zU6bljyRxA4^qUU`2YDx)`}y=x*@+KtSBac>;qcY?zuAd~x7`1fA4n|jeLTA^%I{0R z&%u&I8&&`GCa_jieR-P2?K98qLyM^QzxM~_RzHi!*UqnACyylIHN^Rj+B6T>B0g6wD2rb>45pm~>lr(g1)bIG-PU&x&EkqfVSO*&yS z;hbgfS=;Jm?$a(hPCjqmxW%!3m-FO{289cX=kK>@-tIN=m|6E(zuA|q`_Fk#J#X4| z*0y{tG5mYrJM&be(p=rT6IlmmfW5UU2Hz<2n7J+mwrr-TRF?&V zs_)#7Uw`VB9X@~mmHni1?h{YB&A71m;5DZS7tY*$5wYNs%e3=LkK8nDKjS{>tX=Pg zt!M9fH?R8l@Bi^z&p&_vW!`i4?dR`v_g=Q2d_K5+tzXB6px$jMQ@2gtej$F@_2e0Q z9Xb!V_n&Z^e9@s{ZR~{2!982zCT(|`dj84V&nBH`ww%75u>873@7dlh=bfjXH|{(W z7d!Ji0|SF|NswPKgN%7_eosI1qqlQh)VQ0z2_?Q_-+JKUU7huPe~$OxD4((Q%=1rn z?q4@-&3bU7TsbLBvg!I5S2dYWD;2#S7ZU|h_he3U@wtzOHt*icIpHmL zy?Ai&|Ch$MFYn&^pnlOR%aGe&>)tMux+?e~{z}Q!-sv)H?Z4&ghKAqWlXPcq>ejrS z$BVzazm`65urEF{ge%(WbpDLf>%-W3W7Q8Z-diaxRrFdX{@IL*dsFs5{QGXyqWOP4-1PE)zwr(UqLCNG@BDShIb@BbQOH~rvz6x(1rM{&)h zCI2^1ie0}woOhbaNv}DX8hPC_CNKHouloIxr(aOX;V(s%tEQ{y7mEGo6BjSNdm(Vs z!BXu_x9&`h);d4=?!Ti)lNFxZ-a1{#+&m+>>+vSZ{Dx(nJA39omT)(Wd}d*OchY}> zS=Wlr9G}5lbce-J`;++A6P>4z=5$@YRO0(?M@{jf7aF}sW!InoesgvD`S0uR{y+7c zJM*Z^%fdw#&#l*lSVe4|v9FI;Blz0)M}eM4}1S7y|fO|lGIHmwo6)ysN) z@`Y2E&hx0QzQ6Ic0N5mtVH?#oTPjdTv<|H^U?6ohXl5NmKFtfVaU1XGt93HWL;;RCz(~i-B@2 ztMZwa3;7ji`<>cuYUsWYyyfT~aW>~)Ttdp0haa*^A7`rEIn48j^>mNb9mZLUU;Dgq zb(BBsvZ#Nx_Uel(roBAMoph#Zi{zHxs=z<2V(tqsuD&`oda+X07I6J*oa%H2;&Oq~}6b8UMv1o^cHB zw@!+h7H6D zE$XK?O<(fKWT9kaoQA9NCob2O4UaD6IrQb)Yuwtmc1m82EZ4gF#as5z)n(u0^CphP zQoO8O{?ujuQ*uXBbiS=f+M{6qXZNIC-#wKX9$WmgkWlOGG%UQt>8v8C#bLHj^{?#p zq^}Oqw=ccclsgm}$Rb#}qSsU0T>Y|%q3Of?gq$MZT@r_@Zu{PyecS50-wK8AYV-e2 zfB!+nf3KYzTfhAMRX%I(>aI5GIrFb~>*ZDV4V`!wuLxajKX3Ps*sJFZ{dk2L|LmL? zzat=TpVAF?U;l!InHzU3j`scCuEl+urt8mrgm91(dc6j+tP z6A`%Mx>-aj?~J8<#TLO+mYPp{qlT&iN z&a1S3<*O-TZj{@!u_4N6X2lKeSu#n_P@}6L{b6Jl@&cjG~%U8!&Dx}z( zrMAAcayuD$-&lEawocKa4aqJsJ&X3~rhP8ov`9`;z3BX#j-a~m>C=zc{$M|Ob;m?a ziOFe4?k@Rq<_XD> zB4=;4Zhd?AM&|77+xND~`rPKZmAu(>+oP1++ovkt{rkN7+x4_tFaL!ukK6nGo$YfQ z^*v9n8!cmLEqlSVG%sR-0gvk$*DRbW z{m-p)*DZrjd!y_xaa_#o*4U(@uKo4!Pp!ij7T!1}%l>}rjh7!Q-(N81zW?~clRw*E z{?k)GYWmiy#bRlmL;oJl&J$aiudgm)F0-iHas2Qk`y1cI?%sa8bcrAT(b;!%I<0P9 z{GTy@w!r#Jyj6z3I9)}Su6`_XYb*QXS!FV5bHD9z{itSs)R*aqqTRyE=Ymg+ZNB$v zHnpZ&)$hNave^Ci{e>)>+mm|UX)=F2arlas*Y!VZ^`gp;W=x!PmHFb<*?e}lzMCE0 zvRk9d-y7$jUC*^W@geu4@I-OlYNyz3uMQ~hJ@ZAvR^;ZhPs}lPSAO%o7BSQa zbpPGC@q~NNuAHs@aeMx#hPkYYE#J1MVCVaHeA;*K{uFcFvg=QSSx&=`UA`hqVtqd? zdYU5{zPVBEP0{7r*yQI8{Cgfe_xwDKZM9d}j|Vzyjy`R7nLK@io8wY#kL`E7Jf<68x9vugLJO(0z-KZ&Qdg!24aAb07_69#wwGGo2xYnJYN`~G6Y z{f5WJTvyi~d3Pw}=hJ5XJrB~|HdTa{+%+rHYo0wvW<#>j?DETdO_@vH{3w)qU%ji; z_NZx&{M3G{ii77TKhyiAxALr4;M%-PCKi?|B^8>h(u}9Bzu_-jd+e)R*D9HVSAKyF zecrkG`QJvbip||uzVh)2I2K)AknA*Z-`f1(ke>{yQhV!uK44yNk^b+!z|FQq$H>U% z4;rj)&CipZ6`-=U+SoNLchL;9^D}-vc+R=`7mwnv#>0hg<$|tQStOh|DXSMGs-QM%v9#OT6aOo!0u!OS>mk{4v*^-gU{kUv-=DI!X3RTGs59 zrms7aq`qxvdDNrlbwOV>GmT$cCUm!OcDu!Xn-2~CQ?8YY{CTrg$>;Sw`KWyp56!-# zvTn<7$3qHR4xXKK)bzH)nQ1H9&39e2*J8I>_;hw(^Yq=jSu~fmADQ`g-w!kW*($3f zq`R`zS+DL4=#y?Q`_N(ZtLBi%<=QzX-b%(U=MFlvzxDbXmD0JBS)OidXsr40A^42_ zgQZVg7!FDwD~idOcvfy#ai6Y&gUYVfn=F;xwLJ0PR(xmSKH_ux;D=dz-;~^0xZPL! z1ozroz7KYO?cK)hC-BfMm|Z;L!tIi4FB=3m3Vm8)$!*y6sqlWqio>o2PxU5+TD=Tg zTYBn%ncKVvzMt<;x^8t&I-EsdU*;9>P2#^cg&*=|96!BiOWgcbr%qb!*P729?QZ?6 zRrA<$=6|mncDLWmyzk*RUeFH>vO3!Qi?h`T=KR)_2Cros(q` zrr!L0L#TAiV);U2p+@gxZ`B_y65O@-44>dO5ph1@TNmwv1>fy$%wBo$+&WgT#8pop z)W1KvrsG3JiO}O;u{)0M6cpu=b+0}4U()?P(=nGF;+fwCy{@FkvLxKGX3gAtJaCcS qX{9?EN|FMnBE=+YEB(x$$D3}plVUPRyu-l2z~JfX=d#Wzp$P!`FXGq$ literal 0 HcmV?d00001 diff --git a/src/vendor/images/marker-shadow.png b/src/vendor/images/marker-shadow.png new file mode 100644 index 0000000000000000000000000000000000000000..9fd2979532a19a15b824ce763c76e04a8dafadfb GIT binary patch literal 618 zcmeAS@N?(olHy`uVBq!ia0y~yV9*3%4i*Lm2ByptwG0eQhMq2tAr*{oFSYhPb`W5> zz-9dRf4!`+aT{;(+DlW`OuKvh(cD`Fe?o50tvmGJPyYYkI}^-Pj=%i->5t$_?z+Eg z<0t)EHE)aXMy2F{nEjj_T;IYwdK?Rnnaqjf{1)D-;#kNmzt4GE;O+QxK@S+5(^AaU z7N=aDb)V1U?7Vn^%sUpxJr3q=Te918=e*elN$zhlHIzdXC1oeM8Mbg5Nj2o3WOPw+ zpMOwu*&gweJLb*OS~P7Ar@rLmS*ayg8lq+dZ0+?Zm6nX!yo^w|MJ60@P{_ADQggak&v`^0oPSK8g z6Zm$gzJVJ145{rKZ=dn?y=(KrV#&L&JR6VjWuMu>*SMBLWeLMd-$OHax6Mdiqt~NQ zs^Y#(?6|a*=efdFwcBoGHo3%{*nZNbWKCU{!`kM%S>CBD4~8GC3UcaXD%fwav8F%f z=oGOgmCmZ50aHZd{ Date: Sun, 29 Sep 2024 09:28:50 +0200 Subject: [PATCH 38/43] Map.on: make handler type be (.. -> unit) --- src/map.ml | 2 +- src/map.mli | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/map.ml b/src/map.ml index 3c3ae0e..146055d 100644 --- a/src/map.ml +++ b/src/map.ml @@ -33,7 +33,7 @@ let set_view latlng ~zoom map = in () -let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> t -> unit = +let on : type kind. kind Event.sub -> (kind Event.t -> unit) -> t -> unit = fun event handler map -> let name = Event.sub_to_string event in let handler v = handler @@ Event.of_jv event v in diff --git a/src/map.mli b/src/map.mli index b50e841..4b8db43 100644 --- a/src/map.mli +++ b/src/map.mli @@ -28,7 +28,7 @@ val get_container : t -> Brr.El.t (** [on event handler map] add an event listener on [map] for event [event] with handler [handler] *) -val on : 'a Event.sub -> ('a Event.t -> 'b) -> t -> unit +val on : 'a Event.sub -> ('a Event.t -> unit) -> t -> unit (** [get_center map] is the geographical center of the map view *) val get_center : t -> Latlng.t From 619be59031f495f4f9f39fddd94f40aafa4dcfbb Mon Sep 17 00:00:00 2001 From: Swrup Date: Sun, 15 Dec 2024 06:58:09 +0100 Subject: [PATCH 39/43] ocamlformat --- .ocamlformat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ocamlformat b/.ocamlformat index f948087..eb9f4e0 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version=0.26.2 +version=0.27.0 assignment-operator=end-line break-cases=fit break-fun-decl=wrap From a67ff6acabddf84b6673f397b06160a50402ca64 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 6 Feb 2025 01:28:39 +0100 Subject: [PATCH 40/43] basic example with tiny_httpd --- dune-project | 6 +++-- example/css_path.ml | 14 ---------- example/dune | 29 ++++++++++++++------- example/{map.html => index.html} | 4 +-- example/server.ml | 44 ++++++++++++++++++++++++++++++++ leaflet.opam | 3 ++- 6 files changed, 72 insertions(+), 28 deletions(-) rename example/{map.html => index.html} (68%) create mode 100644 example/server.ml diff --git a/dune-project b/dune-project index 41f5cea..d65af52 100644 --- a/dune-project +++ b/dune-project @@ -30,9 +30,11 @@ (tags (leaflet javascript bindings interactive map openstreetmap)) (depends + (ocaml + (>= 4.08)) brr js_of_ocaml dune-site - (ocaml - (>= 4.08))) + (tiny_httpd :with-test) + ) (sites (share css) (share images))) diff --git a/example/css_path.ml b/example/css_path.ml index 96a5634..e69de29 100644 --- a/example/css_path.ml +++ b/example/css_path.ml @@ -1,14 +0,0 @@ -(* get leaflet.css path from dune-site *) - -let dune_site = List.filter Sys.file_exists Mysites.Sites.css - -let lookup_file filename = - List.find_map - (fun dir -> - let filename' = Filename.concat dir filename in - if Sys.file_exists filename' then Some filename' else None ) - dune_site - -let leaflet_css = lookup_file "leaflet.css" |> Option.get - -let () = Format.printf "%s@." leaflet_css diff --git a/example/dune b/example/dune index 1e537ac..b7b1c0c 100644 --- a/example/dune +++ b/example/dune @@ -1,14 +1,25 @@ -(executable - (name css_path) - (modules css_path mysites) - (libraries dune-site)) - -(generate_sites_module - (module mysites) - (sites leaflet)) - (executable (name script) (modules script) (libraries brr leaflet) (modes js)) + +(executable + (name server) + (modules content server css_path mysites) + (libraries dune-site tiny_httpd)) + +(generate_sites_module + (module mysites) + (sites leaflet)) + +(rule + (with-stdout-to + content.ml + (progn + (echo "let index_html = {|") + (cat index.html) + (echo "|}") + (echo "let script_js = {|") + (cat script.bc.js) + (echo "|}")))) diff --git a/example/map.html b/example/index.html similarity index 68% rename from example/map.html rename to example/index.html index 053dd17..4ba93c9 100644 --- a/example/map.html +++ b/example/index.html @@ -4,12 +4,12 @@ - +
-
+
diff --git a/example/server.ml b/example/server.ml new file mode 100644 index 0000000..755e2ab --- /dev/null +++ b/example/server.ml @@ -0,0 +1,44 @@ +let read_file file = In_channel.with_open_bin file In_channel.input_all + +let leaflet_css = + (* get leaflet.css path from dune-site *) + let dune_site = List.filter Sys.file_exists Mysites.Sites.css in + let lookup_file filename = + List.find_map + (fun dir -> + let filename' = Filename.concat dir filename in + if Sys.file_exists filename' then Some filename' else None ) + dune_site + in + let path = + match lookup_file "leaflet.css" with + | None -> + Printf.eprintf + "File 'leaflet.css' not found.\n\ + It should have been installed with dune-site.\n\ + Did you run `dune build @install`?\n"; + exit 1 + | Some o -> o + in + read_file path + +let script_js = Content.script_js + +let index_html = Content.index_html + +module S = Tiny_httpd + +let () = + let server = S.create () in + S.add_route_handler server + S.Route.(exact "leaflet.css" @/ return) + (fun _req -> S.Response.make_string (Ok leaflet_css)); + S.add_route_handler server + S.Route.(exact "script.js" @/ return) + (fun _req -> S.Response.make_string (Ok script_js)); + S.add_route_handler server + S.Route.(return) + (fun _req -> S.Response.make_string (Ok index_html)); + + Printf.printf "listening on http://%s:%d/\n%!" (S.addr server) (S.port server); + match S.run server with Ok () -> () | Error e -> raise e diff --git a/leaflet.opam b/leaflet.opam index d4db64e..9c0c18f 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -16,10 +16,11 @@ doc: "TODO/leaflet" bug-reports: "https://git.zapashcanon.fr/swrup/leaflet/issues" depends: [ "dune" {>= "2.9"} + "ocaml" {>= "4.08"} "brr" "js_of_ocaml" "dune-site" - "ocaml" {>= "4.08"} + "tiny_httpd" {with-test} "odoc" {with-doc} ] build: [ From 96b4f963a6c2d4173342ba2a50e8dd9903ecf195 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 6 Feb 2025 01:53:13 +0100 Subject: [PATCH 41/43] better readme; rm empty test/ --- README.md | 22 +++++++++++++--------- dune-project | 6 ++---- leaflet.opam | 1 - test/dune | 3 --- test/test.ml | 1 - 5 files changed, 15 insertions(+), 18 deletions(-) delete mode 100644 test/dune delete mode 100644 test/test.ml diff --git a/README.md b/README.md index ffa9b2e..a43ea72 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # leaflet -`leaflet` is an [OCaml] bindings library for the [Leaflet] JavaScript library. +`leaflet` is an [OCaml] bindings library for the [Leaflet] JavaScript library (v1.9.4). ## Installation @@ -16,27 +16,31 @@ If you can't or don't want to use `opam`, consult the [opam file] for build inst ## Usage -Have a look at the [example] folder. -The documentation can be consulted via `odig doc leaflet`. +The library use `dune-site` to install [leaflet's files] (CSS and images). -You will also need [leaflet's files] (CSS and images). +Have a look at the [example] folder. +It use [tiny_httpd] to provide a simple web page with a map that use [OpenStreetMap] tiles: +```sh +dune build @install +dune exec example/server.exe +``` ## About -leaflet's original code was taken from a [NGI0 funded project] +This library started off from the code of a [NGI0 funded project] - [LICENSE] - [CHANGELOG] [CHANGELOG]: ./CHANGES.md -[example]: ./example [LICENSE]: ./LICENSE.md [opam file]: ./leaflet.opam -[test suite]: ./test - [how to install opam]: https://opam.ocaml.org/doc/Install.html [OCaml]: https://ocaml.org [opam]: https://opam.ocaml.org/ [Leaflet]: https://leafletjs.com/ -[leaflet's files]: https://leafletjs.com/download.html +[Leaflet's files]: ./src/vendor/ [NGI0 funded project]: https://nlnet.nl/project/openEngiadina/ +[tiny_httpd]: https://github.com/c-cube/tiny_httpd +[example]: ./example/ +[OpenStreetMap]: https://www.openstreetmap.org diff --git a/dune-project b/dune-project index d65af52..90cc610 100644 --- a/dune-project +++ b/dune-project @@ -5,6 +5,8 @@ (name leaflet) +(generate_opam_files true) + (license BSD-2-Clause) (authors "pukkamustard " "swrup " "Léo Andrès ") @@ -18,10 +20,6 @@ (bug_reports https://git.zapashcanon.fr/swrup/leaflet/issues) -(documentation TODO/leaflet) - -(generate_opam_files true) - (package (name leaflet) (synopsis "Bindings for the Leaflet JavaScript library") diff --git a/leaflet.opam b/leaflet.opam index 9c0c18f..ac98590 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -12,7 +12,6 @@ authors: [ license: "BSD-2-Clause" tags: ["leaflet" "javascript" "bindings" "interactive" "map" "openstreetmap"] homepage: "https://git.zapashcanon.fr/swrup/leaflet" -doc: "TODO/leaflet" bug-reports: "https://git.zapashcanon.fr/swrup/leaflet/issues" depends: [ "dune" {>= "2.9"} diff --git a/test/dune b/test/dune deleted file mode 100644 index f929c11..0000000 --- a/test/dune +++ /dev/null @@ -1,3 +0,0 @@ -(test - (name test) - (modules test)) diff --git a/test/test.ml b/test/test.ml deleted file mode 100644 index 29ef5f9..0000000 --- a/test/test.ml +++ /dev/null @@ -1 +0,0 @@ -let () = assert true (* TODO *) From e15c700d4ba926954aecf65ab20e94f9122f14a0 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 6 Feb 2025 02:39:11 +0100 Subject: [PATCH 42/43] don't generate opam file with dune --- dune-project | 20 +------------------- leaflet.opam | 3 ++- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/dune-project b/dune-project index 90cc610..3227a39 100644 --- a/dune-project +++ b/dune-project @@ -5,28 +5,10 @@ (name leaflet) -(generate_opam_files true) - -(license BSD-2-Clause) - -(authors "pukkamustard " "swrup " "Léo Andrès ") - -(maintainers "swrup ") - -(source - (uri git+https://git.zapashcanon.fr/swrup/leaflet.git)) - -(homepage https://git.zapashcanon.fr/swrup/leaflet) - -(bug_reports https://git.zapashcanon.fr/swrup/leaflet/issues) +(generate_opam_files false) (package (name leaflet) - (synopsis "Bindings for the Leaflet JavaScript library") - (description - "leaflet is an OCaml bindings library for the Leaflet JavaScript library.") - (tags - (leaflet javascript bindings interactive map openstreetmap)) (depends (ocaml (>= 4.08)) diff --git a/leaflet.opam b/leaflet.opam index ac98590..25c8f4d 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -1,5 +1,6 @@ -# This file is generated by dune, edit dune-project instead opam-version: "2.0" +name: "leaflet" +version: "0.2" synopsis: "Bindings for the Leaflet JavaScript library" description: "leaflet is an OCaml bindings library for the Leaflet JavaScript library." From 8e88bbaf67e827296068e410739ffd0c80c8562a Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 23 Nov 2024 09:51:13 +0100 Subject: [PATCH 43/43] version 0.2 --- CHANGES.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 4cff088..0c40b06 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,11 @@ +## 0.2 + +- use leaflet.js v1.9.4 +- some small breaking changes +- add more bindings +- use dune-site to "install" css and images files +- provide example + ## 0.1 Initial release.