module Viewer using Blink using Colors export ConstructionViewer, display!, opentools!, closetools! # === Blink utilities === append_to_head!(w, type, content) = @js w begin @var element = document.createElement($type) element.appendChild(document.createTextNode($content)) document.head.appendChild(element) end style!(w, stylesheet) = append_to_head!(w, "style", stylesheet) script!(w, code) = append_to_head!(w, "script", code) # === construction viewer === mutable struct ConstructionViewer win::Window function ConstructionViewer() # create window and open developer console win = Window(Blink.Dict(:width => 620, :height => 620)) # set stylesheet style!(win, """ body { background-color: #c8c0d0; } /* maximum dimensions are needed to keep Ganja canvas from blowing up */ canvas { min-width: 600px; max-width: 600px; min-height: 600px; max-height: 600px; margin-top: 10px; margin-left: 10px; border-radius: 10px; } """) # load Ganja.js loadjs!(win, "https://unpkg.com/ganja.js") # create global functions and variables script!(win, """ // create algebra var CGA3 = Algebra(4, 1); // initialize element list and palette var elements = []; var palette = []; // declare handles for the visualization and its options var graph; var graphOpt; // create scene function function scene() { commands = []; for (let n = 0; n < elements.length; ++n) { commands.push(palette[n], elements[n]); } return commands; } """) # create view @js win begin graphOpt = Dict( :conformal => true, :gl => true, :grid => true, :devicePixelRatio => window.devicePixelRatio ) graph = CGA3.graph(scene, graphOpt) document.body.replaceChildren(graph) end new(win) end end function display!(viewer::ConstructionViewer, elements::Matrix) # load elements elements_full = [ [0; elt; fill(0, 26)] for elt in eachcol(elements) ] @js viewer.win elements = $elements_full.map((elt) -> @new CGA3(elt)) # generate palette. this is Gadfly's `default_discrete_colors` palette, # available under the MIT license palette = distinguishable_colors( length(elements_full), [LCHab(70, 60, 240)], transform = c -> deuteranopic(c, 0.5), lchoices = Float64[65, 70, 75, 80], cchoices = Float64[0, 50, 60, 70], hchoices = range(0, stop=330, length=24) ) palette_packed = [RGB24(c).color for c in palette] @js viewer.win palette = $palette_packed # update view @js viewer.win requestAnimationFrame(graph.update.bind(graph, scene)); end function opentools!(viewer::ConstructionViewer) size(viewer.win, 1240, 620) opentools(viewer.win) end function closetools!(viewer::ConstructionViewer) closetools(viewer.win) size(viewer.win, 620, 620) end end # ~~~ sandbox setup ~~~ # in the default view, e4 + e5 is the point at infinity elements = sqrt(0.5) * BigFloat[ 1 1 -1 -1 0; 1 -1 1 -1 0; 1 -1 -1 1 0; 0 0 0 0 -sqrt(6); 1 1 1 1 2 ] # show construction viewer = Viewer.ConstructionViewer() Viewer.display!(viewer, elements)