type marker_state = { pos : Leaflet.lat_lng ; name : string ; color : string ; icon : string } let remove state pos = Js.Array.filter (fun m -> m.pos != pos) state let update state previousPos marker = Js.Array.concat [| marker |] (remove state previousPos) let last_added state = if Js.Array.length state > 0 then Some state.(0) else None (* URL Serialization *) let sep = "|" let marker_to_string marker = [| String.format_float 6 marker.pos.lat ; String.format_float 6 marker.pos.lng ; marker.name ; marker.color ; marker.icon |] |> Js.Array.joinWith sep let to_url_string state = state |> Js.Array.map marker_to_string |> Js.Array.joinWith sep |> String.encode let from_url_string str = let (_, _, res) = Js.Array.reduce (fun (acc_str, acc_marker, acc_state) c -> let length = Js.Array.length acc_marker in if c != sep then (acc_str ^ c, acc_marker, acc_state) else if c == sep && length < 4 then ("", Js.Array.concat [| acc_str |] acc_marker, acc_state) else let marker = { pos = { lat = Js.Float.fromString acc_marker.(0) ; lng = Js.Float.fromString acc_marker.(1) } ; name = acc_marker.(2) ; color = acc_marker.(3) ; icon = acc_str } in ("", [| |], Js.Array.concat acc_state [| marker |]) ) ("", [| |], [| |]) (Js.Array.from (Js.String.castToArrayLike ((String.decode str) ^ sep))) in res (* Colors *) let default_color = "#3f92cf" let colors = Js.Array.reduce (fun colors marker -> if Js.Array.indexOf marker.color colors == -1 then Js.Array.concat [| marker.color |] colors else colors) [| |] (* CSV Serialization *) let lat_key = "lat" let lng_key = "lng" let name_key = "name" let color_key = "color" let icon_key = "icon" let to_csv_string state = let to_csv_line marker = [| Js.Float.toString marker.pos.lat ; Js.Float.toString marker.pos.lng ; marker.name ; marker.color ; marker.icon |] in let header = [| lat_key; lng_key; name_key; color_key; icon_key |] in state |> Js.Array.map to_csv_line |> Fun.flip Js.Array.concat [| header |] |> CSV.to_string let from_dicts dicts = Js.Array.map (fun dict -> (* let get key default = Js.Dict.get dict key |> Option.withDefault default in *) { pos = { lat = Js.Dict.get dict lat_key |> Option.map Js.Float.fromString |> Option.withDefault 0.0 ; lng = Js.Dict.get dict lng_key |> Option.map Js.Float.fromString |> Option.withDefault 0.0 } ; name = Js.Dict.get dict name_key |> Option.withDefault "" ; color = Js.Dict.get dict color_key |> Option.withDefault default_color ; icon = Js.Dict.get dict icon_key |> Option.withDefault "" }) dicts