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 (* CSV Serialization *) let to_csv_line marker = [| Js.Float.toString marker.pos.lat ; Js.Float.toString marker.pos.lng ; marker.name ; marker.color ; marker.icon |] |> Js.Array.joinWith "," let to_csv_string state = state |> Js.Array.map to_csv_line |> Fun.flip Js.Array.concat [| "lat,lng,name,color,icon" |] |> Js.Array.joinWith "\n" (* Colors *) 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) [| |]