From ec812521b31471ce9ac3d9bdf1288b1569defbc8 Mon Sep 17 00:00:00 2001 From: Sébastien Dailly Date: Wed, 23 Dec 2020 19:11:31 +0100 Subject: Add svg output --- script.ml | 93 ++++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 22 deletions(-) (limited to 'script.ml') diff --git a/script.ml b/script.ml index 58eae1e..de0b48c 100755 --- a/script.ml +++ b/script.ml @@ -2,21 +2,24 @@ open StdLabels open Note open Brr -module Timer = Events.Timer +module Path_Builder = Path.Builder.Make(Path.Point) -module Repr = Path.FillPrinter +module CanvaRepr = Path.FillPrinter.Make(Layer.CanvaPrinter) +module SVGRepr = Path.WireFramePrinter.Make(Layer.Svg) +module Path_Printer = Path_Builder.Draw(CanvaRepr) +module Fixed_Printer = Path_Builder.DrawFixed(CanvaRepr) -module Path_Builder = Path.Builder.Make(Path.Point) -module Path_Printer = Path_Builder.Draw(Repr) -module Fixed_Printer = Path_Builder.DrawFixed(Repr) +module SVG_Fixed_Printer = Path_Builder.DrawFixed(SVGRepr) + +let expected_host = [%static_hash ""] type mode = | Edit | Selection of Path_Builder.fixedPath | Out -let timer, tick = Timer.create () +let timer, tick = Elements.Timer.create () type current = Path_Builder.t @@ -37,7 +40,9 @@ type canva_events = ] type button_events = - [ `Delete ] + [ `Delete + | `Export + ] type events = [ canva_events @@ -151,7 +156,7 @@ let do_action (* Click anywhere while in Out mode, we switch in edition *) | `Click _, Out -> - Timer.start timer 0.3; + Elements.Timer.start timer 0.3; { state with mode = Edit } (* Click anywhere while in selection mode, we either select another path, @@ -164,15 +169,15 @@ let do_action | Some selected -> (* Start the timer in order to handle the mouse moves *) - Timer.start timer 0.3; + Elements.Timer.start timer 0.3; { state with mode = (Selection selected)} end | `Out point, Edit -> - Timer.stop timer; + Elements.Timer.stop timer; begin match Path_Builder.peek2 state.current with - (** If there is at last two points selected, handle this as a curve + (* If there is at last two points selected, handle this as a curve creation *) | Some _ -> let current, fixed_path = insert_or_replace point state.current in @@ -183,7 +188,7 @@ let do_action { mode = Out ; paths; current } - (** Else, check if there is a curve undre the cursor, and remove it *) + (* Else, check if there is a curve undre the cursor, and remove it *) | None -> let current = Path_Builder.empty in begin match check_selection point state.paths with @@ -202,6 +207,47 @@ let do_action let id = Path_Builder.id s in let paths = List.filter state.paths ~f:(fun p -> Path_Builder.id p != id) in { state with paths ; mode = Out} + + + | `Export, _ -> + + let my_host = Uri.host @@ Window.location @@ G.window in + + if (Hashtbl.hash my_host) = expected_host then ( + (* Convert the path into an sVG element *) + let svg = Layer.Svg.svg + ~at:Brr.At.[ + v (Jstr.v "xmlns") (Jstr.v "http://www.w3.org/2000/svg") + ; v (Jstr.v "xmlns:xlink") (Jstr.v "http://www.w3.org/1999/xlink") ] + (List.map state.paths + ~f:(fun path -> + let repr = SVGRepr.create_path (fun _ -> ()) in + let path = SVGRepr.get @@ SVG_Fixed_Printer.draw path repr in + + Layer.Svg.path + ~at:Brr.At.[ + v (Jstr.v "fill") (Jstr.v "#000000") + ; v (Jstr.v "stroke") (Jstr.v "#000000") + ; v (Jstr.v "d") path ] + [] + )) in + let content = El.prop (El.Prop.jstr @@ Jstr.v "outerHTML") svg in + + let btoa = Jv.get Jv.global "btoa" in + let base64data = Jv.apply btoa + [| Jv.of_jstr content |] in + + (* Create the link to download the the element, and simulate a click on it *) + let a = El.a + ~at:At.[ + href Jstr.( (v "data:image/svg+xml;base64,") + (Jv.Id.of_jv base64data)) + ; v (Jstr.v "download") (Jstr.v "out.svg") + ] + [] in + El.click a + ); + state + | _ -> state let backgroundColor = Jstr.v "#2e3440" @@ -247,18 +293,18 @@ let on_change canva mouse_position state = end in - let path = Repr.get + let path = CanvaRepr.get @@ Path_Printer.draw current - (Repr.create_path (fun p -> fill context p)) in + (CanvaRepr.create_path (fun p -> fill context p)) in stroke context path; List.iter paths ~f:(fun path -> - let path = Repr.get + let path = CanvaRepr.get @@ Fixed_Printer.draw path - (Repr.create_path (fun p -> fill context p)) in + (CanvaRepr.create_path (fun p -> fill context p)) in stroke context path; ); @@ -268,10 +314,10 @@ let on_change canva mouse_position state = | Selection path -> set_fill_style context (color nord8); set_stroke_style context (color nord8); - let path = Repr.get + let path = CanvaRepr.get @@ Fixed_Printer.draw path - (Repr.create_path (fun p -> fill context p)) in + (CanvaRepr.create_path (fun p -> fill context p)) in stroke context path; | _ -> () in () @@ -285,7 +331,7 @@ let page_main id = ; mode = Out } in - let delete_event' = + let delete_event', export_event' = begin match Blog.Sidebar.get () with | None -> Jv.throw (Jstr.v "No sidebar") @@ -295,7 +341,8 @@ let page_main id = let event = Blog.Sidebar.add_button el in event end in - let delete_event = E.map (fun () -> `Delete) delete_event' in + let delete_event = E.map (fun () -> `Delete) delete_event' + and export_event = E.map (fun () -> `Export) export_event' in (*begin match Document.find_el_by_id G.document id with*) @@ -321,7 +368,7 @@ let page_main id = (* The first evaluation is the state. Which is the result of all the successives events to the initial state *) let state = - E.select [canva_events; tick_event; delete_event] + E.select [canva_events; tick_event; delete_event; export_event] |> E.map do_action |> Note.S.accum init in @@ -347,10 +394,12 @@ let page_main id = let () = if Brr_webworkers.Worker.ami () then () - else + else ( + let open Jv in let drawer = obj [| "run", (repr page_main) |] in set global "drawer" drawer + ) -- cgit v1.2.3