(set! compact-end-tag-rendering? #f)
(set! use-empty-tags-for-elements-without-contents #t)
(define current-animation-type 'none)
(define svg-language 'svg11)
(define standard-svg-1-1-element-attributes
(list 'version "1.1"
'baseProfile "full"
'xmlns "http://www.w3.org/2000/svg"
'xmlns:xlink "http://www.w3.org/1999/xlink"))
(define emphasis-color "red")
(define button-color "grey")
(define expl-dur "1s")
(define node-dur "1s")
(define edge-dur "1s")
(define edge-move-dur "3s")
(define disappear-dur "0.5s")
(define infinite 1000000)
(define svg-graph
(xml-in-laml-abstraction
(lambda (cont attr)
(let* ((from-step (as-number (defaulted-get-prop 'from-step attr 0)))
(to-step (as-number (defaulted-get-prop 'to-step attr 0)))
(button-x (as-number (defaulted-get-prop 'button-x attr 0)))
(button-y (as-number (defaulted-get-prop 'button-y attr 24)))
(explanations-ast (traverse-and-collect-first-from-ast cont (ast-of-type? 'element-name "explanations") id-1))
(explanation-font-size (if explanations-ast (ast-attribute explanations-ast 'font-size 20) #f))
(explanation-x (if explanations-ast (as-number (ast-attribute explanations-ast 'x 100)) #f))
(explanation-y (if explanations-ast (as-number (ast-attribute explanations-ast 'y 24 )) #f))
(explanation-width (if explanations-ast (as-number (ast-attribute explanations-ast 'width 500)) #f))
(explanation-height (if explanations-ast (as-number (ast-attribute explanations-ast 'height 50)) #f))
(explanation-list
(if explanations-ast
(traverse-and-collect-all-from-ast explanations-ast (ast-of-type? 'element-name "explanation")
(lambda (expl-ast)
(list (as-number (ast-attribute expl-ast 'step)) (ast-subtrees expl-ast))))
'()))
(explanation-clause
(cond ((and explanations-ast
(or (animation-includes? 'step-buttons-reveal) (animation-includes? 'step-buttons-walk-through)
(animation-includes? 'step-buttons-walk-through-edge-motion)))
(make-explanation-clause explanation-list explanation-x explanation-y explanation-width explanation-height
explanation-font-size from-step to-step))
((and explanations-ast (animation-includes? 'auto))
(make-explanation-clause-auto explanation-list explanation-x explanation-y explanation-width explanation-height
explanation-font-size from-step to-step))
(else '())))
(animation-control
(cond ((or (animation-includes? 'step-buttons-reveal) (animation-includes? 'step-buttons-walk-through) (animation-includes? 'step-buttons-walk-through-edge-motion))
(make-animation-control-clause button-x button-y from-step to-step))
(else '())))
(g-attributes (property-subset attr '()))
(g-cont
(filter (lambda (cnt) (not (and (ast? cnt) (equal? (ast-element-name cnt) "explanations")))) cont))
)
(g (open-arrow-def 20 15) (open-diamond-def 30 22.5) (filled-arrow-def 20 15) (filled-diamond-def 30 22.5)
animation-control explanation-clause
g-cont g-attributes)
))
(required-implied-attributes '() '(from-step to-step button-x button-y)
"svg-graph"
)
"svg-graph"
svg-language))
(define (make-animation-control-clause x y from-step to-step)
(let ((y (- y 8)))
(list
(g
(let ((x (+ x 50))
)
(triangle x (- y 12) (+ x 24) y x (+ y 12)
'fill button-color 'id (animation-forward-button-name from-step) 'css:visibility "visible"
(show-setting-upon (+ from-step 1) 'backward)
(hide-setting-upon from-step 'forward)
)))
(map (lambda (step)
(g
(triangle x y (+ x 24) (- y 12) (+ x 24) (+ y 12)
'fill button-color 'id (animation-backward-button-name step) 'css:visibility "hidden"
(show-setting-upon (- step 1) 'forward) (show-setting-upon (+ step 1) 'backward)
(hide-setting-upon step 'forward) (hide-setting-upon step 'backward)
)
(let ((x (+ x 50)))
(triangle x (- y 12) (+ x 24) y x (+ y 12)
'fill button-color 'id (animation-forward-button-name step) 'css:visibility "hidden"
(show-setting-upon (- step 1) 'forward) (show-setting-upon (+ step 1) 'backward)
(hide-setting-upon step 'forward) (hide-setting-upon step 'backward)
))
))
(number-interval (+ from-step 1) to-step))
(g
(triangle x y (+ x 24) (- y 12) (+ x 24) (+ y 12)
'fill button-color 'id (animation-backward-button-name (+ to-step 1)) 'css:visibility "hidden"
(show-setting-upon to-step 'forward)
(hide-setting-upon (+ to-step 1) 'backward)
)
)
)))
(define (show-setting-upon step direction)
(set 'attributeType "CSS"
'attributeName "visibility" 'to "visible"
'begin
(string-append
(cond ((eq? direction 'forward) (animation-forward-button-name step))
((eq? direction 'backward) (animation-backward-button-name step))
(else (laml-error "show-setting-upon: direction must be either forward or backward" direction)))
"." "click") 'fill "freeze"))
(define (hide-setting-upon step direction)
(set 'attributeType "CSS"
'attributeName "visibility" 'to "hidden"
'begin
(string-append
(cond ((eq? direction 'forward) (animation-forward-button-name step))
((eq? direction 'backward) (animation-backward-button-name step))
(else (laml-error "show-setting-upon: direction must be either forward or backward" direction)))
"." "click") 'fill "freeze"))
(define svg-node
(xml-in-laml-positional-abstraction 3 0
(lambda (shape-path-function x y cont attr)
(let* ((id (defaulted-get-prop 'id attr #f))
(font-size (as-number (defaulted-get-prop 'font-size attr 30)))
(font-family (defaulted-get-prop 'font-family attr "times-roman"))
(text-color (defaulted-get-prop 'text-color attr "black"))
(text-align (defaulted-get-prop 'text-align attr "cc"))
(bg-color (defaulted-get-prop 'bg-color attr "white"))
(locator (defaulted-get-prop 'lc attr "cc"))
(min-width (as-number (defaulted-get-prop 'min-width attr 0)))
(min-height (as-number (defaulted-get-prop 'min-height attr 0)))
(delta-width (as-number (defaulted-get-prop 'delta-width attr 0)))
(delta-height (as-number (defaulted-get-prop 'delta-height attr 0)))
(step (as-number (defaulted-get-prop 'step attr 0)))
(rect-attributes (property-subset attr '(stroke-width stroke stroke-dasharray stroke-offset opacity stroke-opacity rx ry)))
(text-attributes (property-subset attr '(font-style)))
(label-dx (as-number (defaulted-get-prop 'ldx attr 0)))
(label-dy (as-number (defaulted-get-prop 'ldy attr 0)))
(w (+ (max (measured-text-width cont font-size font-family) min-width) delta-width))
(h (+ (max (measured-text-height cont font-size font-family) min-height) delta-height))
(displacement-vector (rectangle-adjustment locator w h))
(dx (car displacement-vector))
(dy (cdr displacement-vector))
(cr-x (+ x dx))
(cr-y (+ y dy))
(text-x-y-clause (text-x-y cr-x cr-y w h font-size text-align label-dx label-dy))
(group-animation-clause
(let* ((step-from (as-number (defaulted-get-prop 'step-from attr step)))
(step-to (as-number (defaulted-get-prop 'step-to attr infinite)))
)
(if (> step-from step-to) (laml-error "step-from must be less than or equal to step-to" step-from step-to))
(cond ((animation-includes? 'step-buttons-reveal)
(list
(if (> step-from 0)
(list 'css:visibility "visible" 'css:opacity 0)
(list 'css:visibility "visible" 'css:opacity 1))
(animate 'attributeType "CSS" 'attributeName "opacity"
(list 'from 0 'to 1) 'dur edge-dur 'fill "freeze"
'begin (string-append (animation-forward-button-name step-from) "." "click"))
(animate 'attributeType "CSS" 'attributeName "opacity"
(list 'from 1 'to 0) 'dur edge-dur 'fill "freeze"
'begin (string-append (animation-forward-button-name step-to) "." "click"))
(animate 'attributeType "CSS" 'attributeName "opacity"
(list 'from 0 'to 1) 'dur disappear-dur 'fill "freeze"
'begin (string-append (animation-backward-button-name (+ step-to 1)) "." "click"))
(animate 'attributeType "CSS" 'attributeName "opacity"
(list 'from 1 'to 0) 'dur disappear-dur 'fill "freeze"
'begin (string-append (animation-backward-button-name (+ step-from 1)) "." "click"))
))
((animation-includes? 'auto)
(let ((start-time (as-number (second current-animation-type)))
(seconds-pr-step (as-number (third current-animation-type))))
(list
(if (> step-from 0)
(list 'css:visibility "visible" 'css:opacity 0)
(list 'css:visibility "visible" 'css:opacity 1))
(animate 'attributeType "CSS" 'attributeName "opacity"
(list 'from 0 'to 1) 'dur edge-dur 'fill "freeze"
'begin (+ start-time (* step-from seconds-pr-step)))
)))
(else '()))))
(rect-animation-clause-node-emphasize
(cond ((animation-includes? 'node-emphasize)
(list
(animate 'attributeType "XML" 'attributeName "fill" 'from bg-color 'to emphasis-color 'dur node-dur
'begin "mouseover" 'fill "freeze")
(animate 'attributeType "XML" 'attributeName "fill" 'from emphasis-color 'to bg-color 'dur disappear-dur
'begin "mouseout" 'fill "freeze")
))
(else '())))
(rect-animation-clause-buttons-walk-through
(let* ((steps-given (as-number-list (defaulted-get-prop 'steps attr "")))
(steps (cond ((not (null? steps-given)) steps-given)
(else (list step)))))
(cond ((or (animation-includes? 'step-buttons-walk-through) (animation-includes? 'step-buttons-walk-through-edge-motion))
(map (lambda (step)
(list
(node-emphasize bg-color (animation-forward-button-name step))
(if (>= step 1)
(node-deemphasize bg-color (animation-forward-button-name (+ step 1)))
'())
(node-deemphasize bg-color (animation-backward-button-name (+ step 1)))
(if (>= step 1)
(node-emphasize bg-color (animation-backward-button-name (+ step 2)))
'())
)) steps))
(else '())))
))
(g group-animation-clause
(shape-path-function cr-x cr-y w h
rect-attributes
'stroke-width "1" 'stroke "black" 'fill bg-color (if id (list 'id id) '())
rect-animation-clause-node-emphasize rect-animation-clause-buttons-walk-through)
(text text-attributes 'font-family font-family 'font-size font-size
'stroke text-color 'color text-color 'fill text-color
text-x-y-clause
cont
)
)))
(required-implied-attributes '() '(id font-size font-family text-color text-align bg-color lc min-width min-height delta-width delta-height
stroke-width stroke stroke-dasharray stroke-offset rx ry font-style step steps step-from step-to)
"svg-node"
)
"svg-node"
svg-language))
(define empty-svg-node
(xml-in-laml-positional-abstraction 2 0
(lambda (x y cont attr)
(svg-node rectangular x y "" 'stroke "none" attr))))
(define (node-emphasize bg-color-before but)
(animate 'attributeType "XML" 'attributeName "fill"
'from bg-color-before 'to emphasis-color 'dur node-dur 'fill "freeze"
'begin (string-append but "." "click")))
(define (node-deemphasize bg-color-after but)
(animate 'attributeType "XML" 'attributeName "fill"
'to bg-color-after 'from emphasis-color 'dur disappear-dur 'fill "freeze"
'begin (string-append but "." "click")))
(define (as-number-list comma-string)
(map as-number (string-to-list comma-string (list #\,))))
(define svg-composite-node
(xml-in-laml-positional-abstraction 3 0
(lambda (x y inner-graph cont attr)
(let* (
(bg-color (defaulted-get-prop 'bg-color attr "white"))
(locator (defaulted-get-prop 'lc attr "cc"))
(padding (as-number (defaulted-get-prop 'padding attr 0)))
(step (as-number (defaulted-get-prop 'step attr 0)))
(steps-given (as-number-list (defaulted-get-prop 'steps attr "")))
(steps (cond ((not (null? steps-given)) steps-given)
(else (list step))))
(rect-attributes (property-subset attr '(stroke-width stroke stroke-dasharray stroke-offset rx ry)))
(min-max-x-y (find-min-max-x-y inner-graph))
(inner-x (first min-max-x-y))
(inner-y (second min-max-x-y))
(width-of-inner-graph (- (third min-max-x-y) (first min-max-x-y)))
(height-of-inner-graph (- (fourth min-max-x-y) (second min-max-x-y)))
(width-of-composite (as-number (defaulted-get-prop 'width attr width-of-inner-graph)))
(height-of-composite (* height-of-inner-graph (divide width-of-composite width-of-inner-graph)))
(displacement-vector (rectangle-adjustment locator (+ width-of-composite (* 2 padding)) (+ height-of-composite (* 2 padding))))
(dx (car displacement-vector))
(dy (cdr displacement-vector))
(cr-x (+ x dx))
(cr-y (+ y dy))
(group-animation-clause
(cond ((animation-includes? 'step-buttons-reveal)
(list
(if (> step 0)
(list 'css:visibility "visible" 'css:opacity 0)
(list 'css:visibility "visible" 'css:opacity 1))
(animate 'attributeType "CSS" 'attributeName "opacity"
'from 0 'to 1 'dur node-dur 'fill "freeze"
'begin (string-append (animation-forward-button-name step) "." "click"))
(animate 'attributeType "CSS" 'attributeName "opacity"
'from 1 'to 0 'dur disappear-dur 'fill "freeze"
'begin (string-append (animation-backward-button-name (+ step 1)) "." "click"))
))
(else '())))
(rect-animation-clause-buttons-walk-through
(cond ((or (animation-includes? 'step-buttons-walk-through) (animation-includes? 'step-buttons-walk-through-edge-motion))
(map (lambda (step)
(list
(node-emphasize bg-color (animation-forward-button-name step))
(if (>= step 1)
(node-deemphasize bg-color (animation-forward-button-name (+ step 1)))
'())
(node-deemphasize bg-color (animation-backward-button-name (+ step 1)))
(if (>= step 1)
(node-emphasize bg-color (animation-backward-button-name (+ step 2)))
'())
)) steps)
)
(else '())))
)
(g group-animation-clause
(rect rect-attributes 'x cr-x 'y cr-y
'width (+ width-of-composite (* 2 padding)) 'height (+ height-of-composite (* 2 padding))
'stroke-width "1" 'stroke "black" 'fill bg-color
rect-animation-clause-buttons-walk-through
)
(g 'transform (svg-translate (+ cr-x padding) (+ cr-y padding) )
(g 'transform (svg-scale (divide width-of-composite width-of-inner-graph))
(g 'transform (svg-translate (- inner-x) (- inner-y)) inner-graph))))))
(required-implied-attributes '() '(step steps padding width bg-color lc min-width min-height
stroke-width stroke stroke-dasharray stroke-offset rx ry font-style)
"svg-compositie-node"
)
"svg-composite-node"
svg-language))
(define (svg-edge . parameters)
(cond ((and (>= (length parameters) 4)
(ast? (first parameters)) (string? (second parameters))
(ast? (third parameters)) (string? (fourth parameters)))
(apply svg-edge-original parameters))
((and (>= (length parameters) 2) (ast? (first parameters)) (ast? (second parameters)))
(apply svg-edge-new parameters))
(else (laml-error "svg-edge: Either (svg-edge node con node con ...) or (svg-edge node node ...)."))))
(define svg-edge-original
(xml-in-laml-positional-abstraction 4 0
(lambda (from-node from-connector to-node to-connector cont attr)
(let* ((arrow (defaulted-get-prop 'arrow attr "no"))
(from-id (defaulted-get-prop 'from-id attr #f))
(to-id (defaulted-get-prop 'to-id attr #f))
(step (as-number (defaulted-get-prop 'step attr 0)))
(font-size (as-number (defaulted-get-prop 'font-size attr 30)))
(font-family (defaulted-get-prop 'font-family attr "times-roman"))
(font-style (defaulted-get-prop 'font-style attr "normal"))
(text-color (defaulted-get-prop 'text-color attr "black"))
(label-dx (as-number (defaulted-get-prop 'ldx attr 0)))
(label-dy (as-number (defaulted-get-prop 'ldy attr 0)))
(edge-style (as-symbol (defaulted-get-prop 'style attr "straight")))
(dx (as-number (defaulted-get-prop 'dx attr 0)))
(dy (as-number (defaulted-get-prop 'dy attr 0)))
(from-pair (x-y-of-node from-node from-id from-connector))
(x1 (+ (car from-pair) dx)) (y1 (+ (cdr from-pair) dy))
(to-pair (x-y-of-node to-node to-id to-connector))
(x2 (+ (car to-pair) dx)) (y2 (+ (cdr to-pair) dy))
(break-path (defaulted-get-prop 'break-path attr #f))
(edge-break-segment (defaulted-get-prop 'break-path attr (edge-break-segment edge-style x1 y1 x2 y2)))
(line-attr (property-subset attr '(stroke stroke-width stroke-dasharray stroke-dashoffset stroke-linecap)))
(forward-line-id (unique-symbol "line"))
(reverse-line-id (unique-symbol "line"))
(stroke-width (as-number (defaulted-get-prop 'stroke-width attr 1)))
(stroke (defaulted-get-prop 'stroke attr "black"))
(duration (ensure-as-seconds (defaulted-get-prop 'dur attr edge-move-dur)))
(arrow-clause
(cond ((or (equal? arrow "yes") (equal? arrow "true") (equal? arrow "filled-triangle") (equal? arrow "triangle")) (list 'marker-end "url(#FilledArrowhead)"))
((equal? arrow "open-triangle") (list 'marker-end "url(#OpenArrowhead)") )
((or (equal? arrow "diamond") (equal? arrow "filled-diamond")) (list 'marker-end "url(#FilledDiamond)"))
((equal? arrow "open-diamond") (list 'marker-end "url(#OpenDiamond)"))
(else '())) )
(group-animation-clause
(let ((step-from (as-number (defaulted-get-prop 'step-from attr step)))
(step-to (as-number (defaulted-get-prop 'step-to attr infinite)))
)
(if (> step-from step-to) (laml-error "step-from must be less than or equal to step-to" step-from step-to))
(cond ((animation-includes? 'step-buttons-reveal)
(list
(if (> step-from 0)
(list 'css:visibility "visible" 'css:opacity 0)
(list 'css:visibility "visible" 'css:opacity 1))
(animate 'attributeType "CSS" 'attributeName "opacity"
(list 'from 0 'to 1) 'dur edge-dur 'fill "freeze"
'begin (string-append (animation-forward-button-name step-from) "." "click"))
(animate 'attributeType "CSS" 'attributeName "opacity"
(list 'from 1 'to 0) 'dur edge-dur 'fill "freeze"
'begin (string-append (animation-forward-button-name step-to) "." "click"))
(animate 'attributeType "CSS" 'attributeName "opacity"
(list 'from 0 'to 1) 'dur disappear-dur 'fill "freeze"
'begin (string-append (animation-backward-button-name (+ step-to 1)) "." "click"))
(animate 'attributeType "CSS" 'attributeName "opacity"
(list 'from 1 'to 0) 'dur disappear-dur 'fill "freeze"
'begin (string-append (animation-backward-button-name (+ step-from 1)) "." "click"))
))
((animation-includes? 'auto)
(let ((start-time (as-number (second current-animation-type)))
(seconds-pr-step (as-number (third current-animation-type))))
(list
(if (> step-from 0)
(list 'css:visibility "visible" 'css:opacity 0)
(list 'css:visibility "visible" 'css:opacity 1))
(animate 'attributeType "CSS" 'attributeName "opacity"
(list 'from 0 'to 1) 'dur edge-dur 'fill "freeze"
'begin (+ start-time (* step-from seconds-pr-step))))
))
(else '()))))
(line-animation-clause-edge-emphasize
(cond ((animation-includes? 'edge-emphasize)
(list
(animate 'attributeType "XML" 'attributeName "stroke-width" 'from stroke-width 'to (* 4 stroke-width)
'dur edge-dur 'begin "mouseover" 'fill "freeze")
(animate 'attributeType "XML" 'attributeName "stroke-width" 'to stroke-width 'from (* 4 stroke-width)
'dur disappear-dur 'begin "mouseout" 'fill "freeze")
(animate 'attributeType "XML" 'attributeName "stroke" 'from stroke 'to emphasis-color
'dur edge-dur 'begin "mouseover" 'fill "freeze")
(animate 'attributeType "XML" 'attributeName "stroke" 'to stroke 'from emphasis-color
'dur disappear-dur 'begin "mouseout" 'fill "freeze")
))
(else '())))
(line-animation-clause-buttons-walk-through
(let* ((steps-given (as-number-list (defaulted-get-prop 'steps attr "")))
(steps (cond ((not (null? steps-given)) steps-given)
(else (list step))))
)
(cond ((animation-includes? 'step-buttons-walk-through)
(map (lambda (step)
(list
(edge-emphasize stroke stroke-width (animation-forward-button-name step))
(if (>= step 1)
(edge-deemphasize stroke stroke-width (animation-forward-button-name (+ step 1)))
'())
(edge-deemphasize stroke stroke-width (animation-backward-button-name (+ step 1)))
(if (>= step 1)
(edge-emphasize stroke stroke-width (animation-backward-button-name (+ step 2)))
'())
)) steps))
(else '()))))
(group-animation-clause-edge-motion
(let* ((steps-given (as-number-list (defaulted-get-prop 'steps attr "")))
(steps (cond ((not (null? steps-given)) steps-given)
(else (list step))))
)
(cond ((animation-includes? 'step-buttons-walk-through-edge-motion)
(map (lambda (step)
(list
(edge-move forward-line-id (animation-forward-button-name step) duration)
(edge-move reverse-line-id (animation-backward-button-name (+ step 1)) duration)
)) steps)
)
(else '()))))
)
(g group-animation-clause group-animation-clause-edge-motion
(path 'id forward-line-id line-attr 'fill "none"
'd (am-p x1 y1 (append-path edge-break-segment (al-p x2 y2 (e-p))))
'stroke stroke 'stroke-width stroke-width
arrow-clause line-animation-clause-edge-emphasize line-animation-clause-buttons-walk-through)
(path 'id reverse-line-id line-attr 'fill "none" 'css:visibility "hidden"
'd (am-p x2 y2 (append-path edge-break-segment (al-p x1 y1 (e-p))))
'stroke stroke 'stroke-width stroke-width
arrow-clause line-animation-clause-edge-emphasize line-animation-clause-buttons-walk-through)
(text 'font-family font-family 'font-size font-size 'font-style font-style
'stroke text-color 'color text-color 'fill text-color
'x (+ (+ x1 (divide (- x2 x1) 2)) label-dx) 'y (+ (+ y1 (divide (- y2 y1) 2)) label-dy)
cont)
)))
(required-implied-attributes '() '(from-id to-id arrow stroke-width stroke stroke-dasharray
stroke-linecap stroke-dashoffset step steps step-from step-to
dx dy ldx ldy break-path style font-size font-style text-color dur)
"svg-edge"
)
"svg-edge"
svg-language))
(define svg-edge-new
(xml-in-laml-positional-abstraction 2 0
(lambda (from-node to-node cont attr)
(let* ((from-id (defaulted-get-prop 'from-id attr #f))
(to-id (defaulted-get-prop 'to-id attr #f))
(from-connector (defaulted-get-prop 'from-connector attr (default-connection-between from-node from-id to-node to-id)))
(to-connector (defaulted-get-prop 'to-connector attr (default-connection-between to-node to-id from-node from-id))) )
(svg-edge from-node from-connector to-node to-connector cont attr)))))
(define (default-connection-between node node-id other-node other-id)
(let* ((node-xy (basis-x-y-of-node node node-id))
(x (car node-xy))
(y (cdr node-xy))
(other-xy (basis-x-y-of-node other-node other-id))
(ox (car other-xy))
(oy (cdr other-xy))
)
(string-append
(cond ((= x ox) "c")
((> x ox) "l")
((< x ox) "r"))
(cond ((= y oy) "c")
((> y oy) "t")
((< y oy) "b")))))
(define (default-connection-between node node-id other-node other-id)
(let* ((node-xy (basis-x-y-of-node node node-id))
(x (car node-xy))
(y (cdr node-xy))
(other-xy (basis-x-y-of-node other-node other-id))
(ox (car other-xy))
(oy (cdr other-xy))
(xot (- ox x))
(yot (- oy y))
)
(string-append
(cond ((and (>= xot (- yot)) (>= xot yot)) "rc")
((and (<= xot yot) (>= xot (- yot))) "cb")
((and (<= xot yot) (<= xot (- yot))) "lc")
((and (<= xot (- yot)) (>= xot yot)) "ct")
(else (laml-error "default-connection-between: Should not happen"))))))
(define svg-edge-broken
(xml-in-laml-positional-abstraction 5 0
(lambda (from-node from-connector to-node to-connector node-break-list cont attr)
(let ((break-path (node-list-to-edge-break-path node-break-list)))
(svg-edge from-node from-connector to-node to-connector cont attr 'break-path break-path)))))
(define (edge-break-segment edge-style x1 y1 x2 y2)
(cond ((eq? edge-style 'straight) (e-p))
((eq? edge-style 'hv) (rh-p (- x2 x1) (e-p)))
((eq? edge-style 'vh) (rv-p (- y2 y1) (e-p)))
(else (laml-error "edge-break-segment: Unknown edge style" edge-style))))
(define (node-list-to-edge-break-path node-list)
(cond ((null? node-list) (e-p))
(else (let* ((node (car node-list))
(x-y (x-y-of-node node #f "cc")))
(al-p (car x-y) (cdr x-y)
(node-list-to-edge-break-path (cdr node-list)))))))
(define (edge-move line-id but-name duration)
(let ((anim-id (string-append "anim-" line-id)))
(circle 'r 8 'cx 0 'cy 0 'fill emphasis-color 'stroke emphasis-color 'css:visibility "hidden"
(set 'attributeType "CSS" 'attributeName "visibility" 'to "visible" 'begin (string-append but-name "." "click"))
(animateMotion 'id anim-id 'dur duration 'rotate "auto"
'begin (string-append but-name "." "click")
(mpath 'xlink:href (string-append "#" line-id)))
(set 'attributeType "CSS" 'attributeName "visibility" 'to "hidden" 'begin (string-append anim-id ".end")))))
(define (edge-emphasize stroke-before stroke-width-before but-name)
(list
(animate 'attributeType "XML" 'attributeName "stroke" 'from stroke-before 'to emphasis-color
'dur edge-dur 'fill "freeze"
'begin (string-append but-name "." "click"))
(animate 'attributeType "XML" 'attributeName "stroke-width" 'from stroke-width-before 'to (max 5 (* 2 stroke-width-before))
'dur edge-dur 'fill "freeze"
'begin (string-append but-name "." "click"))))
(define (edge-deemphasize stroke-before stroke-width-before but-name)
(list
(animate 'attributeType "XML" 'attributeName "stroke" 'to stroke-before
'from emphasis-color 'dur disappear-dur 'fill "freeze"
'begin (string-append but-name "." "click"))
(animate 'attributeType "XML" 'attributeName "stroke-width" 'to stroke-width-before
'from (max 5 (* 2 stroke-width-before)) 'dur disappear-dur 'fill "freeze"
'begin (string-append but-name "." "click"))
)
)
(define (text-x-y cr-x cr-y w h font-size text-align-locator ldx ldy)
(let* ((hl (horizontal-locator text-align-locator))
(vl (vertical-locator text-align-locator))
(wh (divide w 2))
(hh (divide h 2))
(hor-contribution
(cond ((eq? hl 'c) (list 'x (+ (+ cr-x wh) ldx) 'text-anchor "middle"))
((eq? hl 'l) (list 'x (+ (+ cr-x 5) ldx) 'text-anchor "start"))
((eq? hl 'r) (list 'x (+ (+ cr-x w (- 5)) ldx) 'text-anchor "end"))))
(ver-contribution
(cond ((eq? vl 'c) (list 'y (+ (+ cr-y hh (+ (quotient font-size 2)) (- 5)) ldy)))
((eq? vl 't) (list 'y (+ (+ cr-y font-size) ldy)))
((eq? vl 'b) (list 'y (+ (+ cr-y h (- 5)) ldy)))))
)
(append hor-contribution ver-contribution)))
(define (open-arrow-def w h)
(defs
(marker 'id "OpenArrowhead"
'viewBox "0 0 10 10" 'refX "10" 'refY "5"
'stroke "black" 'stroke-width "1" 'fill "white"
'markerUnits "userSpaceOnUse"
'markerWidth w 'markerHeight h
'orient "auto" 'preserveAspectRatio "none"
(path 'd "M 0 0 L 10 5 L 0 10 z"))))
(define (filled-arrow-def w h)
(defs
(marker 'id "FilledArrowhead"
'viewBox "0 0 10 10" 'refX "10" 'refY "5" 'fill "black"
'fill "black"
'markerUnits "userSpaceOnUse"
'markerWidth w 'markerHeight h
'orient "auto" 'preserveAspectRatio "none"
(path 'd "M 0 0 L 10 5 L 0 10 z"))))
(define (open-diamond-def w h)
(defs
(marker 'id "OpenDiamond"
'viewBox "0 -5 10 10" 'refX "10" 'refY "0"
'stroke "black" 'stroke-width "1" 'fill "white"
'markerUnits "userSpaceOnUse"
'markerWidth w 'markerHeight h
'orient "auto" 'preserveAspectRatio "none"
(path 'd "M 0 0 L 5 -5 L 10 0 L 5 5 z"))))
(define (filled-diamond-def w h)
(defs
(marker 'id "FilledDiamond"
'viewBox "0 -5 10 10" 'refX "10" 'refY "0"
'fill "black"
'markerUnits "userSpaceOnUse"
'markerWidth w 'markerHeight h
'orient "auto" 'preserveAspectRatio "none"
(path 'd "M 0 0 L 5 -5 L 10 0 L 5 5 z"))))
(define (x-y-of-node node-ast id con)
(letrec ((node-interesting? (lambda (node-ast)
(and ((ast-of-type? 'element-name "rect") node-ast)
(equal? (ast-attribute node-ast 'id #f) id)))))
(let* ((rect-ast-1 (find-first-ast node-ast "rect"))
(rect-ast-2 (traverse-and-collect-first-from-ast node-ast node-interesting? id-1))
(rect-ast (if (and id rect-ast-2)
rect-ast-2
rect-ast-1))
(rect-attr (ast-attributes rect-ast))
(x (as-number (get-prop 'x rect-attr)))
(y (as-number (get-prop 'y rect-attr)))
(w (as-number (get-prop 'width rect-attr)))
(h (as-number (get-prop 'height rect-attr)))
(hl (horizontal-locator con))
(vl (vertical-locator con))
)
(cons
(cond ((eq? hl 'c) (+ x (divide w 2)))
((eq? hl 'l) x)
((eq? hl 'r) (+ x w)))
(cond ((eq? vl 'c) (+ y (divide h 2)))
((eq? vl 't) y)
((eq? vl 'b) (+ y h)))))))
(define (basis-x-y-of-node node-ast id)
(letrec ((node-interesting? (lambda (node-ast)
(and ((ast-of-type? 'element-name "rect") node-ast)
(equal? (ast-attribute node-ast 'id #f) id)))))
(let* ((rect-ast-1 (find-first-ast node-ast "rect"))
(rect-ast-2 (traverse-and-collect-first-from-ast node-ast node-interesting? id-1))
(rect-ast (if (and id rect-ast-2)
rect-ast-2
rect-ast-1))
(rect-attr (ast-attributes rect-ast))
(x (as-number (get-prop 'x rect-attr)))
(y (as-number (get-prop 'y rect-attr)))
(w (as-number (get-prop 'width rect-attr)))
(h (as-number (get-prop 'height rect-attr)))
)
(cons (+ x (divide w 2)) (+ y (divide h 2))))))
(define (rectangle-adjustment locator-string width height)
(let ((hl (horizontal-locator locator-string))
(vl (vertical-locator locator-string))
)
(cons
(cond ((eq? hl 'c) (- (divide width 2)))
((eq? hl 'l) 0)
((eq? hl 'r) (- width)))
(cond ((eq? vl 'c) (- (divide height 2)))
((eq? vl 't) 0)
((eq? vl 'b) (- height))))))
(define (find-min-max-x-y svg-graph-ast)
(letrec ((reduce-right (lambda (f lst)
(if (null? (cdr lst))
(car lst)
(f (car lst)
(reduce-right f (cdr lst))))))
(x-y-w-h (lambda (rect-ast)
(let ((rect-attr (ast-attributes rect-ast)))
(list (as-number (get-prop 'x rect-attr)) (as-number (get-prop 'y rect-attr)) (as-number (get-prop 'width rect-attr)) (as-number (get-prop 'height rect-attr))))))
(min-list (lambda (lst) (reduce-right min lst)))
(max-list (lambda (lst) (reduce-right max lst)))
)
(let* ((rect-list (find-asts svg-graph-ast "rect"))
(x-y-w-h-list (map x-y-w-h rect-list))
(x1-y1-x2-y2-list (map (lambda (x-y-w-y-entry) (list (first x-y-w-y-entry) (second x-y-w-y-entry)
(+ (first x-y-w-y-entry) (third x-y-w-y-entry)) (+ (second x-y-w-y-entry) (fourth x-y-w-y-entry))))
x-y-w-h-list))
)
(list
(min-list (map first x1-y1-x2-y2-list))
(min-list (map second x1-y1-x2-y2-list))
(max-list (map third x1-y1-x2-y2-list))
(max-list (map fourth x1-y1-x2-y2-list))))))
(define (horizontal-locator locator-string)
(let ((ls (as-string locator-string)))
(check-locator-string! ls)
(as-symbol (string-ref ls 0))))
(define (vertical-locator locator-string)
(let ((ls (as-string locator-string)))
(check-locator-string! ls)
(as-symbol (string-ref ls 1))))
(define (locator-string? x)
(and (string? x)
(= 2 (string-length x))
(let ((a (string-ref x 0))
(b (string-ref x 1)))
(and (or (eqv? a #\c) (eqv? a #\l) (eqv? a #\r))
(or (eqv? b #\c) (eqv? b #\t) (eqv? b #\b))))))
(define (check-locator-string! ls)
(if (not (locator-string? ls))
(laml-error "Invalid locator string:" ls ". " "First char either c, l, or t. Second char either c, t, or b.")))
(define (animation-includes? animation-kind)
(cond ((symbol? current-animation-type)
(eq? animation-kind current-animation-type))
((list? current-animation-type)
(memq animation-kind current-animation-type))
(else (laml-error "animation-includes?: animation-kind must be a symbol or a list of symbols:" animation-kind))))
(define explanations
(xml-in-laml-abstraction
(lambda (cont attr)
(make-ast "explanations" cont attr 'double svg-language))
(required-implied-attributes '() '(x y font-size width height)
"explanations"
)
"explanations"
svg-language))
(define explanation
(xml-in-laml-abstraction
(lambda (cont attr)
(make-ast "explanation" cont attr 'double svg-language))
(required-implied-attributes '() '(step)
"explanation"
)
"explanation"
svg-language))
(define (make-explanation-clause explanation-list x y width height font-size from-step to-step)
(let ((explanation-list-completed (complete-explanation-list explanation-list to-step)))
(map
(lambda (step-expl)
(let ((step (car step-expl))
(expl (cadr step-expl))
(text-color "black")
)
(g 'css:visibility "visible" 'css:opacity (if (= step 0) 1 0)
(show-explanation-upon step 'forward)
(show-explanation-upon (+ 2 step) 'backward)
(hide-explanation-upon (+ step 1) 'forward)
(hide-explanation-upon (+ step 1) 'backward)
(text 'font-family "times-roman" 'font-size font-size
'stroke text-color 'color text-color 'fill text-color
'x x 'y y expl))))
explanation-list-completed)))
(define (make-explanation-clause-auto explanation-list x y width height font-size from-step to-step)
(let ((explanation-list-completed (complete-explanation-list explanation-list to-step)))
(map
(lambda (step-expl)
(let ((step (car step-expl))
(expl (cadr step-expl))
(text-color "black")
(start-time (as-number (second current-animation-type)))
(seconds-pr-step (as-number (third current-animation-type)))
)
(g 'css:visibility "visible" 'css:opacity (if (= step 0) 1 0)
(animate 'attributeType "CSS" 'attributeName "opacity" 'from 0 'to 1 'dur expl-dur 'fill "freeze"
'begin (+ start-time (* step seconds-pr-step)))
(animate 'attributeType "CSS" 'attributeName "opacity" 'from 1 'to 0 'dur "0.1s" 'fill "freeze"
'begin (+ start-time (* (+ step 1) seconds-pr-step)))
(text 'font-family "times-roman" 'font-size font-size
'stroke text-color 'color text-color 'fill text-color
'x x 'y y expl))))
explanation-list-completed)))
(define (complete-explanation-list explanation-list to-step)
(let ((sorted-explanation-list (sort-list explanation-list (lambda (x y) (<= (car x) (car y))))))
(complete-explanation-list-1 sorted-explanation-list 0 to-step)))
(define (complete-explanation-list-1 sorted-explanation-list i to-step)
(let ((empty-expl ""))
(cond ((and (> i to-step) (null? sorted-explanation-list)) '())
((and (<= i to-step) (null? sorted-explanation-list))
(cons (list i empty-expl) (complete-explanation-list-1 sorted-explanation-list (+ i 1) to-step)))
((= i (car (car sorted-explanation-list)))
(cons (car sorted-explanation-list) (complete-explanation-list-1 (cdr sorted-explanation-list) (+ i 1) to-step)))
(else
(cons (list i empty-expl) (complete-explanation-list-1 sorted-explanation-list (+ i 1) to-step))))))
(define (show-explanation-upon step direction)
(animate 'attributeType "CSS" 'attributeName "opacity" 'from 0 'to 1 'dur expl-dur 'fill "freeze"
'begin (string-append
(cond ((eq? direction 'forward) (animation-forward-button-name step))
((eq? direction 'backward) (animation-backward-button-name step))
(else (laml-error "show-explanation-upon: direction must be either forward or backward" direction)))
"." "click")))
(define (hide-explanation-upon step direction)
(animate 'attributeType "CSS" 'attributeName "opacity" 'from 1 'to 0 'dur "0.1s" 'fill "freeze"
'begin (string-append
(cond ((eq? direction 'forward) (animation-forward-button-name step))
((eq? direction 'backward) (animation-backward-button-name step))
(else (laml-error "hide-explanation-upon: direction must be either forward or backward" direction)))
"." "click")))
(define (rectangular x y w h . attributes)
(rect 'x x 'y y 'width w 'height h
attributes
'stroke-width "1" 'stroke "black"))
(define (circular x y w h . attributes)
(rect 'x x 'y y 'width w 'height h 'rx (divide w 2) 'ry (divide h 2) attributes 'stroke-width "1" 'stroke "black"))
(define (diamond x y w h . attributes)
(let* ((hh (divide h 2)) (wh (divide w 2))
(sx x) (sy (+ y hh)))
(g
(rect 'css:visibility "hidden" 'x x 'y y 'width w 'height h attributes 'stroke-width "1" 'stroke "black")
(path attributes 'd (am-p sx sy (rl-p wh (- hh) (rl-p wh hh (rl-p (- wh) hh (rl-p (- wh) (- hh) (e-p))))))))))
(define (triangular x y w h . attributes)
(let* ((hh (divide h 2)) (wh (divide w 2))
(sx x) (sy (+ y h)))
(g
(rect 'css:visibility "hidden" 'x x 'y y 'width w 'height h attributes 'stroke-width "1" 'stroke "black")
(path attributes 'd (am-p sx sy (rl-p wh (- h) (rl-p wh h (rl-p (- w) 0 (e-p)))))))))
(define (cloud x y w h . attributes)
(let* ((h2 (divide h 2)) (w2 (divide w 2))
(h4 (divide h2 2)) (w4 (divide w2 2))
(sx x) (sy (+ y h2))
(c (divide (+ w h) 8)) (c2 (divide c 2)) (cm (- c)) (cm2 (- c2))
)
(g
(rect 'css:visibility "hidden" 'x x 'y y 'width w 'height h attributes 'stroke-width "1" 'stroke "black")
(path attributes
'd (am-p sx sy
(rq-p 0 cm w4 (- h4)
(rq-p 0 cm w4 (- h4)
(rq-p c cm2 w4 h4
(rq-p c cm w4 h4
(rq-p c c (- w4) h4
(rq-p c c (- w4) h4
(rq-p cm2 c (- w4) (- h4)
(rq-p cm2 c (- w4) (- h4)
(e-p))))))))))))))
(define-syntax with-animation
(syntax-rules ()
((with-animation animation-type form ...)
(let ((old-animation-type current-animation-type))
(set! current-animation-type animation-type)
(let ((result (begin form ...)))
(set! current-animation-type old-animation-type)
result)))))
(define (svg-translate tx ty)
(string-append "translate" "(" (as-string tx) "," (as-string ty) ")"))
(define (svg-scale sx . optional-parameter-list)
(let ((sy (optional-parameter 1 optional-parameter-list sx)))
(string-append "scale" "(" (as-string sx) "," (as-string sy) ")")))
(define (svg-rotate angle . optional-parameter-list)
(let ((cx (optional-parameter 1 optional-parameter-list #f))
(cy (optional-parameter 2 optional-parameter-list #f)))
(if (and cx cy)
(string-append "rotate" "(" (as-string angle) "," (as-string cx) "," (as-string cy) ")")
(string-append "rotate" "(" (as-string angle) ")"))))
(define (svg-skewX angle)
(string-append "skewX" "(" (as-string angle) ")"))
(define (svg-skewY angle)
(string-append "skewY" "(" (as-string angle) ")"))
(define (e-p) "")
(define (al-p x y path) (p-exp "L" path x y))
(define (rl-p x y path) (p-exp "l" path x y))
(define (ah-p x path) (p-exp "H" path x))
(define (rh-p x path) (p-exp "h" path x))
(define (av-p y path) (p-exp "V" path y))
(define (rv-p y path) (p-exp "v" path y))
(define (rm-p x y path) (p-exp "m" path x y))
(define (am-p x y path) (p-exp "M" path x y))
(define (ra-p rx ry x-axis-rotation large-arc? sweep? x y path)
(let ((large-arc-number (as-01-boolean large-arc?))
(sweep-number (as-01-boolean sweep?)))
(p-exp "a" path rx ry x-axis-rotation large-arc-number sweep-number x y)))
(define (aa-p rx ry x-axis-rotation large-arc? sweep? x y path)
(let ((large-arc-number (as-01-boolean large-arc?))
(sweep-number (as-01-boolean sweep?)))
(p-exp "A" path rx ry x-axis-rotation large-arc-number sweep-number x y)))
(define (rq-p cx cy x y path)
(p-exp "q" path cx cy x y))
(define (aq-p cx cy x y path)
(p-exp "Q" path cx cy x y))
(define (rt-p x y path)
(p-exp "t" path x y))
(define (at-p x y path)
(p-exp "T" path x y))
(define (rc-p cx1 cy1 cx2 cy2 x y path)
(p-exp "c" path cx1 cy1 cx2 cy2 x y))
(define (ac-p cx1 cy1 cx2 cy2 x y path)
(p-exp "C" path cx1 cy1 cx2 cy2 x y))
(define (rs-p cx2 cy2 x y path)
(p-exp "s" path cx2 cy2 x y))
(define (as-p cx2 cy2 x y path)
(p-exp "S" path cx2 cy2 x y))
(define (z-p) "Z")
(define (append-path p1 p2)
(string-append p1 p2))
(define (p-exp letter path . coordinates)
(string-append
letter " "
(list-to-string (map as-string coordinates) " ")
" " path))
(define (svg-path? x) (string? x))
(define (divide x y)
(/ (exact->inexact x) (exact->inexact y)))
(define unique-number 0)
(define (unique-symbol prefix)
(set! unique-number (+ unique-number 1))
(string-append prefix "-" (as-string unique-number)))
(define (animation-forward-button-name step-number)
(string-append "forward-button-id" "-" (as-string step-number)))
(define (animation-backward-button-name step-number)
(string-append "backward-button-id" "-" (as-string step-number)))
(define (animation-button-text-name step-number)
(string-append "button-text-id" "-" (as-string step-number)))
(define triangle
(xml-in-laml-positional-abstraction 6 0
(lambda (x1 y1 x2 y2 x3 y3 cont attr)
(path 'd (am-p x1 y1 (al-p x2 y2 (al-p x3 y3 (z-p)))) cont attr))))
(define text-box
(xml-in-laml-abstraction
(lambda (cont attr)
(let* ((x (get-prop 'x attr))
(y (get-prop 'y attr))
(width (get-prop 'width attr))
(height (get-prop 'width attr))
(font-family (defaulted-get-prop 'font-family attr "times-roman"))
(font-size (as-number (defaulted-get-prop 'font-size attr "30")))
)
(do-text-box x y width height font-family font-size cont)
)
)
(required-implied-attributes '(x y width height) '(text-color font-family font-size)
"text-box"
)
"text-box"
svg-language))
(define (do-text-box x y width height font-family font-size text-list)
(laml-error "STOP")
)
(define text-width-factor 1.9)
(define (measured-text-width text-contents font-size font-family)
(let* ((textual? (textual-contents? text-contents))
(txt (if textual? (string-of-textual-contents text-contents) #f))
(basis-width (as-number font-size))
)
(if textual?
(+ (* (/ font-size text-width-factor) (string-length txt)) basis-width)
0)
))
(define (measured-text-height text-contents font-size font-family)
(+ font-size 10))
(define (textual-contents? x)
(cond ((string? x) #t)
((list? x)
(not (find-in-list ast? x)))
(else (laml-error "textual-contents?: Unknown type of parameter:" x))))
(define (string-of-textual-contents x)
(if (string? x)
x
(aggregated-ast-cdata-contents-1 x "")
))
(define (ensure-as-seconds x)
(cond ((number? x) (string-append (as-string x) "s"))
((and (string? x) (eqv? #\s (string-ref x (- (string-length x) 1)))) x)
((string? x) (string-append x "s"))
(else (laml-error "ensure-as-seconds: Cannot ensure x as seconds:" x))))